幾個(gè)場(chǎng)景
首先,讓我先來(lái)帶您瀏覽幾個(gè) ChangingThePresent.org 中的頁(yè)面吧。我將顯示站點(diǎn)中幾個(gè)需要緩存的地方。然后,再指出我們?yōu)槠渲忻總€(gè)地方所做出的選擇以及為實(shí)現(xiàn)這些頁(yè)面所使用的代碼或策略。尤其會(huì)重點(diǎn)討論如下內(nèi)容:
- 全靜態(tài)頁(yè)面
- 幾乎無(wú)變化的全動(dòng)態(tài)的頁(yè)面
- 動(dòng)態(tài)頁(yè)面片段
- 應(yīng)用程序數(shù)據(jù)
先來(lái)看看靜態(tài)頁(yè)面。幾乎每個(gè)站點(diǎn)都會(huì)有靜態(tài)頁(yè)面,如圖 1 所示,其中還有我們的條款和條件??梢酝ㄟ^(guò)單擊 register 然后再選擇是否接受用戶(hù)協(xié)議來(lái)瀏覽相應(yīng)頁(yè)面。對(duì)于 ChangingThePresent 而言,我們從此頁(yè)中刪除了所有動(dòng)態(tài)內(nèi)容以便 Apache 能夠?qū)λM(jìn)行緩存。按照我們 Apache 中配置的規(guī)則,這些內(nèi)容永遠(yuǎn)都不會(huì)由 Rails 服務(wù)器生成。因此,我根本無(wú)需對(duì)其考慮 Rails 緩存。
圖 1. 用戶(hù)協(xié)議
接下來(lái),再來(lái)看看全動(dòng)態(tài)頁(yè)面。理論上講,ChangingThePresent 可以有一些動(dòng)態(tài)構(gòu)建的頁(yè)面,但是這些頁(yè)面一般很少變化。由于幾乎所有頁(yè)面都會(huì)顯示用戶(hù)是否登錄,因此我們并不怎么關(guān)注這種緩存。
再下來(lái),看看頁(yè)面分段緩存。圖 2 中所示的主頁(yè)原來(lái)是完全靜態(tài)的,現(xiàn)在,有一些元素變成了動(dòng)態(tài)的。每天,頁(yè)面都會(huì)顯示一系列禮物,這些禮物有的是隨機(jī)選的,有的則由我們的管理員選定。請(qǐng)注意在標(biāo)題為 “A Few of our Special Gifts for Mother's Day” 節(jié)下的那些禮物,同時(shí)也請(qǐng)注意在最右邊顯示為 “l(fā)ogin.” 的那個(gè)鏈接。此鏈接取決于用戶(hù)是否登錄。我們不能緩存整個(gè)頁(yè)。頁(yè)面每天只能改變一次。
圖 2. 主頁(yè)
最后再考慮應(yīng)用程序。除非是在 15 年之前進(jìn)行網(wǎng)絡(luò)沖浪,否則您現(xiàn)在遇到的有趣站點(diǎn)全部都是動(dòng)態(tài)的?,F(xiàn)代的應(yīng)用程序大都分層,而且可以通過(guò)在層間添加緩存來(lái)使這些分層更加有效。ChangingThePresent 在數(shù)據(jù)庫(kù)層采用了一些緩存。接下來(lái),我將深入討論不同類(lèi)型的緩存,還會(huì)介紹我們?yōu)?ChangingThePresent 都采用了何種緩存。
緩存靜態(tài)內(nèi)容
Mongrel 是一種 Web 服務(wù)器,由 Zed Shaw 利用 2500 行 Ruby 和 C 編寫(xiě)而成。這個(gè)小型的服務(wù)器占用內(nèi)存極少,非常適合 Ruby Web 應(yīng)用程序,例如 Rails、Nitro、Iowa 等等。Mongrel 可運(yùn)行于 UNIX? 和 Linux? 上,也可運(yùn)行在 Win32 上。Mongrel 也經(jīng)??梢宰鳛榇磉\(yùn)行在另一個(gè) Web 服務(wù)器(例如 Apache 或 Litespeed)的后端,但這不是必需的 —— 因?yàn)?Mongrel 是一種 HTTP 服務(wù)器,可以與所有您偏好的 HTTP 工具結(jié)合使用。
除了圖像之外,有關(guān)緩存靜態(tài)數(shù)據(jù)的內(nèi)容,可講的內(nèi)容不多。由于我們的網(wǎng)站是一個(gè)慈善性質(zhì)的門(mén)戶(hù)網(wǎng)站,這意味著我們需要更多地關(guān)注用戶(hù)的感受,比如多加入一些圖像或視頻。但我們的 Web 服務(wù)器 Mongrel 并不能很好地服務(wù)靜態(tài)數(shù)據(jù),因此我們使用 Apache 來(lái)服務(wù)圖像內(nèi)容。
我們現(xiàn)在正在著手轉(zhuǎn)向采用圖形加速器 Panther Express 來(lái)緩存最經(jīng)常被使用的圖像以使其能夠更快地被我們的客戶(hù)訪問(wèn)到。要采取這種策略,我們將需要一個(gè)子域 images.changingThePresent.org。Panther Express 直接在圖像的本地緩存中提供圖像服務(wù),然后再向我們發(fā)送請(qǐng)求。由于 Panther 服務(wù)并不知道我們何時(shí)會(huì)更改圖像,所以我們使用 HTTP 報(bào)頭來(lái)使其到期失效,如下所示:
HTTP 緩存失效報(bào)頭
HTTP/1.1 200 OK
Cache-Control: max-age=86400, must-revalidate
Expires: Tues, 17 Apr 2007 11:43:51 GMT
Last-Modified: Mon, 16 Apr 2007 11:43:51 GMT
注意這些不是 HTML 報(bào)頭。它們與 Web 頁(yè)面內(nèi)容獨(dú)立構(gòu)建。Web 服務(wù)器將負(fù)責(zé)構(gòu)建這些 HTTP 報(bào)頭。像這樣一篇有關(guān) Rails 的文章系列若詳細(xì)介紹 Web 服務(wù)器配置,未免有點(diǎn)偏題,所以我將直接切入可用 Rails 框架進(jìn)行控制的緩存內(nèi)容這一主題(有關(guān) Web 服務(wù)器配置的更多內(nèi)容,請(qǐng)參見(jiàn) 參考資料 中的相關(guān)鏈接)。
頁(yè)面緩存
如果動(dòng)態(tài)頁(yè)面不經(jīng)常更改,可以使用頁(yè)面級(jí)的緩存。比如,Blog 和公告牌使用的就是這種緩存。通過(guò)頁(yè)面緩存,Rails 就可以用來(lái)構(gòu)建動(dòng)態(tài) HTML 頁(yè),并將此頁(yè)存儲(chǔ)在公共目錄,這樣,應(yīng)用程序服務(wù)器就可以像服務(wù)其他靜態(tài)頁(yè)面一樣來(lái)服務(wù)這個(gè)動(dòng)態(tài)頁(yè)。
如果頁(yè)面已經(jīng)被緩存,那么就不需要引入 Rails,頁(yè)面緩存是 Rails 內(nèi)速度最快的一種緩存。在最底層,頁(yè)面緩存實(shí)際上在 Rails 中非常容易實(shí)現(xiàn)。頁(yè)面和分段緩存二者均在控制器級(jí)別發(fā)生。您需要告知 Rails 如下內(nèi)容:
- 想要緩存哪些頁(yè)面?
- 當(dāng)頁(yè)面內(nèi)容更改時(shí),您如何能在緩存中讓該頁(yè)面到期失效?
可以通過(guò)在控制器類(lèi)中使用 caches_page 指令來(lái)啟用頁(yè)面緩存。例如,若要在 about_us_controller 緩存 privacy_policy 和 user_agreement 頁(yè)面,可以輸入如下代碼:
清單 2. 啟用頁(yè)面緩存
class AboutController ApplicationController
caches_page :privacy_policy, :user_agreement
end
讓頁(yè)面到期失效則可以通過(guò) expire_page 指令來(lái)實(shí)現(xiàn)。若要在 Rails 調(diào)用 new_pages 動(dòng)作時(shí)使上述頁(yè)面到期失效,可以使用如下代碼:
清單 3. 使頁(yè)面失效
class AboutController ApplicationController
caches_page :privacy_policy, :user_agreement
def new_pages
expire_page :action => :privacy_policy
expire_page :action => :user_agreement
end
end
另外,有幾個(gè)小問(wèn)題需要注意,比如 URL。URL 不能依賴(lài)于 URL 參數(shù)。例如,應(yīng)該使用 gifts/water/1 而非 gifts/water?page=1。在 routes.rb 中使用這類(lèi) URL 將非常容易。比如,我們的頁(yè)面中總是有一個(gè)選項(xiàng)卡參數(shù)用來(lái)顯示哪個(gè)選項(xiàng)卡被當(dāng)前選中。若要將此選項(xiàng)卡作為 URL 的一部分,我們會(huì)有如下的路由規(guī)則:
清單 4. 選項(xiàng)卡的路由規(guī)則
復(fù)制代碼 代碼如下:
map.connect 'member/:id/:tab', :controller => 'profiles', :action => 'show'
對(duì)于具有頁(yè)面參數(shù)的那些列表以及依賴(lài)于 URL 參數(shù)的其他頁(yè)面,也需要采用相同的做法。此外,還需要考慮安全性問(wèn)題。
如果頁(yè)面已經(jīng)在緩存內(nèi),那么就不會(huì)用到 Rails 框架,服務(wù)器并不能為您管理安全性。Web 服務(wù)器將更樂(lè)于在緩存內(nèi)呈現(xiàn)任何頁(yè)面,而不管用戶(hù)是否對(duì)其擁有查看的權(quán)限。所以,如果您很關(guān)心頁(yè)面可由誰(shuí)查看,那么就不要使用頁(yè)面緩存。
如果只是想緩存簡(jiǎn)單的靜態(tài)頁(yè)面,那么了解上述內(nèi)容就應(yīng)該足夠了。只要內(nèi)容簡(jiǎn)單,實(shí)現(xiàn)起來(lái)就不難。
當(dāng)想要緩存更為復(fù)雜的內(nèi)容時(shí),就需要進(jìn)行一些權(quán)衡取舍了。由于想要緩存的頁(yè)面高度動(dòng)態(tài),所以到期失效邏輯就會(huì)變得更加復(fù)雜。要處理復(fù)雜的到期失效邏輯,將需要編寫(xiě)和配置定制清理器(sweeper)。在某些控制器擊發(fā)時(shí),這些類(lèi)會(huì)從緩存內(nèi)刪除選定的元素。
多數(shù)定制清理器都會(huì)觀察某些模型對(duì)象,并根據(jù)更改擊發(fā)邏輯來(lái)使一個(gè)或多個(gè)緩存頁(yè)面到期失效。清單 5 顯示了一種典型的緩存清理器。在此清理器中,開(kāi)發(fā)人員可以定義一個(gè)活動(dòng)記錄事件,比如 after_save。當(dāng)此事件擊發(fā)時(shí),清理器也會(huì)擊發(fā),并可讓緩存內(nèi)的特定頁(yè)面到期失效。這個(gè)事例所顯示的到期失效基于 expire_page 方法。而很多嚴(yán)格的應(yīng)用程序大都直接使用 Ruby 優(yōu)秀的文件系統(tǒng)實(shí)用工具來(lái)顯式地刪除所緩存的頁(yè)面。
清單 5. 一個(gè)典型的觀察器
class CauseController ApplicationController
cache_sweeper :cause_sweeper
...
class CauseSweeper ActionController::Caching::Sweeper
observe Cause
def after_save(record)
expire_page(:controller => 'causes', :action => 'show',
:id => record.id)
cause.nonprofits.each do |nonprofit|
expire_page(:controller => 'nonprofits', :action => 'show',
:id => nonprofit.id)
end
end
end
現(xiàn)在,您可能會(huì)開(kāi)始感覺(jué)到頁(yè)面緩存的些許缺點(diǎn)了:復(fù)雜性。您雖然可以很好地進(jìn)行頁(yè)面級(jí)的緩存,但固有的復(fù)雜性卻讓?xiě)?yīng)用程序很難測(cè)試,進(jìn)而會(huì)增加系統(tǒng)內(nèi)出現(xiàn) bug 的可能性。而且,如果頁(yè)面針對(duì)每個(gè)用戶(hù)都會(huì)有所不同,或者希望緩存進(jìn)行過(guò)身份驗(yàn)證的頁(yè)面,那么將需要使用頁(yè)面緩存之外的方式。對(duì)于 ChangingThePresent,我們必須處理兩種情況,原因是我們必須基于用戶(hù)是否登錄來(lái)更改基本布局上的鏈接。對(duì)于大多數(shù)頁(yè)面,我們甚至都不會(huì)考慮使用頁(yè)面級(jí)緩存。為了讓您能夠深入了解頁(yè)面級(jí)的緩存,在本文的 參考資料 部分,我特意給出了到一系列有關(guān)頁(yè)面級(jí)緩存的優(yōu)秀文章的鏈接。接下來(lái),將來(lái)深入探究另一種形式的整頁(yè)緩存 —— 動(dòng)作緩存。
動(dòng)作緩存
至此,您已經(jīng)了解了頁(yè)面緩存的主要的優(yōu)勢(shì)及主要的缺點(diǎn):對(duì)于多數(shù)頁(yè)面檢索而言,根本無(wú)需考慮使用 Rails。頁(yè)面緩存的優(yōu)勢(shì)是速度快。缺點(diǎn)是缺少靈活性。如果想要基于應(yīng)用程序內(nèi)的條件 — 例如,身份認(rèn)證 — 來(lái)緩存整個(gè)頁(yè)面,那么可以使用動(dòng)作緩存。
動(dòng)作緩存與頁(yè)面緩存的工作方式大體相同,但在流程上稍有差別。Rails 在呈現(xiàn)動(dòng)作前會(huì)實(shí)際調(diào)用控制器。如果由該動(dòng)作呈現(xiàn)的頁(yè)面已經(jīng)存在于緩存內(nèi),那么 Rails 就會(huì)在緩存內(nèi)呈現(xiàn)頁(yè)面而不是重新加以呈現(xiàn)。由于現(xiàn)在使用了 Rails,因此動(dòng)作緩存的速度要比頁(yè)面緩存慢一些,但其優(yōu)點(diǎn)還是很明顯的。幾乎所有的 Rails 認(rèn)證模式都會(huì)在控制器上使用 before 過(guò)濾器。動(dòng)作緩存讓您能夠利用認(rèn)證及控制器上的任何過(guò)濾器。
從語(yǔ)句構(gòu)成的角度來(lái)看,動(dòng)作緩存與頁(yè)面緩存也應(yīng)該十分類(lèi)似,只有指令不太一樣。清單 6 顯示了如何使用 caches_action 指令。
清單 6. 啟用動(dòng)作緩存
class AboutController ApplicationController
caches_action :secret_page, :secret_list
end
緩存到期失效以及清理器的工作方式也應(yīng)該相同。我們不使用動(dòng)作緩存的原因與我們不使用頁(yè)面緩存的原因是一樣的,但分段緩存對(duì)我們來(lái)說(shuō)更重要一些。
緩存頁(yè)面分段
借助部分緩存,可以緩存頁(yè)面的一部分,所緩存的內(nèi)容很多時(shí)候都是布局之類(lèi)的。要使用分段緩存,開(kāi)發(fā)人員需要先確定分段,方法是通過(guò)在 Web 頁(yè)面上直接放上 rhtml 指令來(lái)包圍一塊內(nèi)容,如清單 7 所示。在 ChangingThePresent.org 上,我們使用分段緩存來(lái)緩存首頁(yè)和其他的幾頁(yè)。所有的這些頁(yè)均使用了數(shù)據(jù)庫(kù)密集訪問(wèn)而且大都是我們最受歡迎的頁(yè)面。
清單 7. 確定緩存分段
% cache 'gifts_index' do %>
h3>
Here, you can make the world a better place with a single gift. Donation gifts
are also a wonderful way to honor friends and family. Just imagine what we
can achieve together.
/h3>
h2 class="lightBlue">%= @event_title %>/h2>
div id="homefeatureitems">
% for gift in @event_gifts %>
%= render :partial => 'gifts/listable', :locals => { :gift => gift } %>
% end %>
/div>
...
% end %>
在清單 7 中,cache 幫助程序標(biāo)識(shí)所要緩存的分區(qū)。第一個(gè)參數(shù)是標(biāo)識(shí)此緩存分區(qū)的惟一名稱(chēng)。第二個(gè)參數(shù)包含代碼塊 — 即第一個(gè) do 和最后一個(gè) end 之間的代碼 — 此代碼塊準(zhǔn)確地確定了要緩存的 RHTML 分區(qū)。
我們的網(wǎng)站只有一個(gè)主頁(yè),所以命名這個(gè)頁(yè)面非常容易。在其他地方,我們使用一種特定的方法來(lái)決定此網(wǎng)頁(yè)的 URL 以便惟一標(biāo)識(shí)緩存分段。例如,當(dāng)我們?yōu)樘囟ǖ膬?nèi)容(比如世界和平或減少貧困)而進(jìn)行代碼緩存時(shí),我們需要使用清單 8 中的代碼。代碼會(huì)為之尋找永久 url,也稱(chēng)為 permalink。
清單 8. 通過(guò) URL 標(biāo)識(shí)緩存分段
% cache @cause.permalink(params[:id]) do %>
通常,當(dāng)緩存單獨(dú)頁(yè)面時(shí),需要用清理器使之過(guò)期失效。有時(shí),使用簡(jiǎn)單的基于時(shí)間的對(duì)象過(guò)期更為容易和簡(jiǎn)潔。默認(rèn)地,Rails 并不提供這類(lèi)機(jī)制,但有一種插件名為 timed_fragment_cache 可以實(shí)現(xiàn)這一目的。借助這個(gè)插件,我可以指定超時(shí),可以在緩存了的內(nèi)容中指定,也可以在為此頁(yè)提供了動(dòng)態(tài)數(shù)據(jù)的控制器代碼中指定。例如,清單 9 所示的代碼就可以為此頁(yè)面構(gòu)建動(dòng)態(tài)數(shù)據(jù)。when_fragment_expired 方法只有在相關(guān)的緩存分段過(guò)期時(shí)才會(huì)執(zhí)行。此方法接受參數(shù),用來(lái)指定超時(shí)的時(shí)長(zhǎng),它還接受一個(gè)代碼塊,用來(lái)指定當(dāng)內(nèi)容過(guò)期時(shí)哪些內(nèi)容需要重建。我也可以選擇在 rhtml 頁(yè)面中指定超時(shí)和緩存方法,但我更愿意使用基于控制器的方法。
清單 9. 基于時(shí)間的緩存到期
def index
when_fragment_expired 'causes_list', 15.minutes.from_now do
@causes = Cause.find_all_ordered
end
end
如果能夠容忍數(shù)據(jù)稍微有些陳舊,那么使用定時(shí)的到期機(jī)制將可以極大地簡(jiǎn)化緩存策略。對(duì)于每個(gè)被緩存的元素,只需指定想要緩存的內(nèi)容、可生成動(dòng)態(tài)內(nèi)容的任何控制器動(dòng)作以及超時(shí)。與頁(yè)面緩存類(lèi)似,如果需要,也可以使用 expire_fragment :controller => controller, :action => action, :id => id 方法顯式讓內(nèi)容到期。此方法的工作方式與緩存動(dòng)作和緩存頁(yè)面的到期失效是一樣的。接下來(lái),我將介紹如何配置此后端。
Memcached
至此為止,我已經(jīng)介紹了 Ruby on Rails 的頁(yè)面和分段緩存模型。看過(guò)了 API 之后,現(xiàn)在就可以定義緩存后的數(shù)據(jù)的去處了。默認(rèn)地,Rails 將把緩存后的頁(yè)面放入文件系統(tǒng)。緩存后的頁(yè)面和動(dòng)作都會(huì)進(jìn)入公共目錄??梢耘渲镁彺婧蟮姆侄蔚拇鎯?chǔ)位置。為此,需要用到內(nèi)存存儲(chǔ)、文件系統(tǒng)(在所定義的目錄)、數(shù)據(jù)庫(kù)或稱(chēng)為 memcached 的服務(wù)。對(duì)于 ChangingThePresent.org,我們使用 memcached。
可以將 Memcached 想象為一個(gè)大型的 hash 圖,這個(gè)圖可通過(guò)網(wǎng)絡(luò)獲得?;趦?nèi)存的緩存速度快,而基于網(wǎng)絡(luò)的緩存的可伸縮性比較好。有了插件支持,Rails 就可使用 memcached 來(lái)緩存分段和 ActiveRecord 模型。要使用它,需要安裝 memcached(更多信息,請(qǐng)參看 參考資料)并在 environment.rb(或其他的環(huán)境配置文件,比如 production.rb)對(duì)它進(jìn)行配置。
清單 10. 配置緩存
config.action_controller.perform_caching = true
memcache_options = {
:c_threshold => 10_000,
:compression => false,
:debug => false,
:readonly => false,
:urlencode => false,
:ttl => 300,
:namespace => 'igprod',
:disabled => false
}
CACHE = MemCache.new memcache_options
清單 10 顯示了一種典型的配置,其中第一行 config.action_controller.perform_caching = true 將啟用緩存。接下來(lái)的一行將準(zhǔn)備緩存選項(xiàng)。注意,這里的諸多選項(xiàng)是為了讓您可以獲得更多的調(diào)試數(shù)據(jù)、禁用緩存和定義該緩存的名稱(chēng)空間。在 參考資料 部分給出的 memcached 站點(diǎn)可以找到有關(guān)配置選項(xiàng)的更多信息。
模型緩存
我們使用的最后一種緩存是基于模型的緩存。我們使用的是稱(chēng)為 CachedModel 的緩存插件的一種定制版本。模型緩存實(shí)際上是一種有限形式的數(shù)據(jù)庫(kù)緩存。緩存很容易按模型啟用。
要想讓模型使用緩存解決方案,只需擴(kuò)展 CachedModel 類(lèi),而非擴(kuò)展 ActiveRecord,如清單 11 所示。 CachedModel 擴(kuò)展 ActiveRecord::Base。ActiveRecord 并非全對(duì)象關(guān)系型映射層。此框架極大地依賴(lài)于 SQL 來(lái)執(zhí)行復(fù)雜的特性,而且如果需要,用戶(hù)可以很容易降至 SQL。直接使用 SQL 會(huì)使緩存出問(wèn)題,因?yàn)榫彺鎸颖仨毺幚硗暾慕Y(jié)果集,而不是單獨(dú)一個(gè)數(shù)據(jù)庫(kù)行。處理完整的結(jié)果集常常會(huì)問(wèn)題不斷,而且如果沒(méi)有支持應(yīng)用程序的深層邏輯,這幾乎不太可能。正由于這個(gè)原因,CachedModel 的焦點(diǎn)才會(huì)放到緩存單個(gè)模型對(duì)象上,并只加速返回單行結(jié)果的查詢(xún)。
清單 11. 使用 CachedModel
大多數(shù) Rails 應(yīng)用程序都會(huì)重復(fù)訪問(wèn)多個(gè)條目,例如用戶(hù)對(duì)象。模型緩存在很多情況下都可以明顯地使速度加快。對(duì)于 ChangingThePresent,我們剛剛開(kāi)始加速基于模型的緩存。
結(jié)束語(yǔ)
Ruby 雖然是一門(mén)生產(chǎn)率極高的語(yǔ)言,但若從性能角度考慮,該語(yǔ)言解釋性的特性讓它并不那么理想。大多數(shù)主要的 Rails 應(yīng)用程序都將會(huì)通過(guò)有效利用緩存來(lái)彌補(bǔ)某些不足。對(duì)于 ChangingThePresent.org,我們主要使用分段緩存,并通過(guò)控制器使用基于時(shí)間的方法來(lái)使緩存分段到期失效。這種方式很適合我們的網(wǎng)站,即使其中有一些頁(yè)面會(huì)基于登錄進(jìn)來(lái)的用戶(hù)有所變化。
我們還研究了使用受 memcached 支撐的 CachedModel 類(lèi)所能帶來(lái)的影響。雖然我們的研究還僅限于緩存對(duì)數(shù)據(jù)庫(kù)性能所造成的影響,但早期的結(jié)果還是很有希望的。在 下一篇 文章中,我將介紹一些實(shí)用技巧,您可以使用這些技巧來(lái)為另一個(gè)真實(shí)世界中的 Rails 示例進(jìn)行數(shù)據(jù)庫(kù)優(yōu)化。
您可能感興趣的文章:- 在localStorage中存儲(chǔ)對(duì)象數(shù)組并讀取的方法
- 詳解JavaScript中l(wèi)ocalStorage使用要點(diǎn)
- android webview 中l(wèi)ocalStorage無(wú)效的解決方法
- JS localStorage實(shí)現(xiàn)本地緩存的方法
- 使用jquery讀取html5 localstorage的值的方法
- Android使用緩存機(jī)制實(shí)現(xiàn)文件下載及異步請(qǐng)求圖片加三級(jí)緩存
- PHP緩存機(jī)制Output Control詳解
- jQuery的緩存機(jī)制淺析
- 簡(jiǎn)單的php緩存類(lèi)分享 php緩存機(jī)制
- 移動(dòng)端使用localStorage緩存Js和css文的方法(web開(kāi)發(fā))
- localStorage的黑科技-js和css緩存機(jī)制