H5 緩存機制淺析 移動端 Web 載入性能優化

来源:http://www.cnblogs.com/8hao/archive/2016/03/01/5230588.html
-Advertisement-
Play Games

1 H5 緩存機制介紹 H5,即 HTML5,是新一代的 HTML 標準,加入很多新的特性。離線存儲(也可稱為緩存機制)是其中一個非常重要的特性。H5 引入的離線存儲,這意味著 web 應用可進行緩存,並可在沒有網際網路連接時進行訪問。 H5 應用程式緩存為應用帶來三個優勢: 離線瀏覽 用戶可在應用離


1 H5 緩存機制介紹

H5,即 HTML5,是新一代的 HTML 標準,加入很多新的特性。離線存儲(也可稱為緩存機制)是其中一個非常重要的特性。H5 引入的離線存儲,這意味著 web 應用可進行緩存,並可在沒有網際網路連接時進行訪問。

H5 應用程式緩存為應用帶來三個優勢:

  • 離線瀏覽 用戶可在應用離線時使用它們

  • 速度 已緩存資源載入得更快

  • 減少伺服器負載 瀏覽器將只從伺服器下載更新過或更改過的資源。

根據標準,到目前為止,H5 一共有6種緩存機制,有些是之前已有,有些是 H5 才新加入的。

  1. 瀏覽器緩存機制

  2. Dom Storgage(Web Storage)存儲機制

  3. Web SQL Database 存儲機制

  4. Application Cache(AppCache)機制

  5. Indexed Database (IndexedDB)

  6. File System API

下麵我們首先分析各種緩存機制的原理、用法及特點;然後針對 Anroid 移動端 Web 性能載入優化的需求,看如果利用適當緩存機制來提高 Web 的載入性能。

2 H5 緩存機制原理分析

2.1 瀏覽器緩存機制

瀏覽器緩存機制是指通過 HTTP 協議頭裡的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等欄位來控制文件緩存的機制。這應該是 WEB 中最早的緩存機制了,是在 HTTP 協議中實現的,有點不同於 Dom Storage、AppCache 等緩存機制,但本質上是一樣的。可以理解為,一個是協議層實現的,一個是應用層實現的。

Cache-Control 用於控制文件在本地緩存有效時長。最常見的,比如伺服器回包:Cache-Control:max-age=600 表示文件在本地應該緩存,且有效時長是600秒(從發出請求算起)。在接下來600秒內,如果有請求這個資源,瀏覽器不會發出 HTTP 請求,而是直接使用本地緩存的文件。

Last-Modified 是標識文件在伺服器上的最新更新時間。下次請求時,如果文件緩存過期,瀏覽器通過 If-Modified-Since 欄位帶上這個時間,發送給伺服器,由伺服器比較時間戳來判斷文件是否有修改。如果沒有修改,伺服器返回304告訴瀏覽器繼續使用緩存;如果有修改,則返回200,同時返回最新的文件。

Cache-Control 通常與 Last-Modified 一起使用。一個用於控制緩存有效時間,一個在緩存失效後,向服務查詢是否有更新。

Cache-Control 還有一個同功能的欄位:Expires。Expires 的值一個絕對的時間點,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在這個時間點之前,緩存都是有效的。

Expires 是 HTTP1.0 標準中的欄位,Cache-Control 是 HTTP1.1 標準中新加的欄位,功能一樣,都是控制緩存的有效時間。當這兩個欄位同時出現時,Cache-Control 是高優化級的。

Etag 也是和 Last-Modified 一樣,對文件進行標識的欄位。不同的是,Etag 的取值是一個對文件進行標識的特征字串。在向伺服器查詢文件是否有更新時,瀏覽器通過 If-None-Match 欄位把特征字串發送給伺服器,由伺服器和文件最新特征字串進行匹配,來判斷文件是否有更新。沒有更新回包304,有更新回包200。Etag 和 Last-Modified 可根據需求使用一個或兩個同時使用。兩個同時使用時,只要滿足基中一個條件,就認為文件沒有更新。

另外有兩種特殊的情況:

  • 手動刷新頁面(F5),瀏覽器會直接認為緩存已經過期(可能緩存還沒有過期),在請求中加上欄位:Cache-Control:max-age=0,發包向伺服器查詢是否有文件是否有更新。

  • 強制刷新頁面(Ctrl+F5),瀏覽器會直接忽略本地的緩存(有緩存也會認為本地沒有緩存),在請求中加上欄位:Cache-Control:no-cache(或 Pragma:no-cache),發包向服務重新拉取文件。

下麵是通過 Google Chrome 瀏覽器(用其他瀏覽器+抓包工具也可以)自帶的開發者工具,對一個資源文件不同情況請求與回包的截圖。

首次請求:200

Vh8bpPi.gif

緩存有效期內請求:200(from cache)

q36bsW4.gif

緩存過期後請求:304(Not Modified)

xKsdLUS.gif

一般瀏覽器會將緩存記錄及緩存文件存在本地 Cache 文件夾中。Android 下 App 如果使用 Webview,緩存的文件記錄及文件內容會存在當前 app 的 data 目錄中。

分析:Cache-Control 和 Last-Modified 一般用在 Web 的靜態資源文件上,如 JS、CSS 和一些圖像文件。通過設置資源文件緩存屬性,對提高資源文件載入速度,節省流量很有意義,特別是移動網路環境。但問題是:緩存有效時長該如何設置?如果設置太短,就起不到緩存的使用;如果設置的太長,在資源文件有更新時,瀏覽器如果有緩存,則不能及時取到最新的文件。

Last-Modified 需要向伺服器發起查詢請求,才能知道資源文件有沒有更新。雖然伺服器可能返回304告訴沒有更新,但也還有一個請求的過程。對於移動網路,這個請求可能是比較耗時的。有一種說法叫“消滅304”,指的就是優化掉304的請求。

抓包發現,帶 if-Modified-Since 欄位的請求,如果伺服器回包304,回包帶有 Cache-Control:max-age 或 Expires 欄位,文件的緩存有效時間會更新,就是文件的緩存會重新有效。304回包後如果再請求,則又直接使用緩存文件了,不再向伺服器查詢文件是否更新了,除非新的緩存時間再次過期。

另外,Cache-Control 與 Last-Modified 是瀏覽器內核的機制,一般都是標準的實現,不能更改或設置。以 QQ 瀏覽器的 X5為例,Cache-Control 與 Last-Modified 緩存不能禁用。緩存容量是12MB,不分HOST,過期的緩存會最先被清除。如果都沒過期,應該優先清最早的緩存或最快到期的或文件大小最大的;過期緩存也有可能還是有效的,清除緩存會導致資源文件的重新拉取。

還有,瀏覽器,如 X5,在使用緩存文件時,是沒有對緩存文件內容進行校驗的,這樣緩存文件內容被修改的可能。

分析發現,瀏覽器的緩存機制還不是非常完美的緩存機制。完美的緩存機制應該是這樣的:

  1. 緩存文件沒更新,儘可能使用緩存,不用和伺服器交互;

  2. 緩存文件有更新時,第一時間能使用到新的文件;

  3. 緩存的文件要保持完整性,不使用被修改過的緩存文件;

  4. 緩存的容量大小要能設置或控制,緩存文件不能因為存儲空間限制或過期被清除。

    以X5為例,第1、2條不能同時滿足,第3、4條都不能滿足。

在實際應用中,為瞭解決 Cache-Control 緩存時長不好設置的問題,以及為了”消滅304“,Web前端採用的方式是:

  1. 在要緩存的資源文件名中加上版本號或文件 MD5值字串,如 common.d5d02a02.js,common.v1.js,同時設置 Cache-Control:max-age=31536000,也就是一年。在一年時間內,資源文件如果本地有緩存,就會使用緩存;也就不會有304的回包。

  2. 如果資源文件有修改,則更新文件內容,同時修改資源文件名,如 common.v2.js,html頁面也會引用新的資源文件名。

通過這種方式,實現了:緩存文件沒有更新,則使用緩存;緩存文件有更新,則第一時間使用最新文件的目的。即上面說的第1、2條。第3、4條由於瀏覽器內部機制,目前還無法滿足。

2.2 Dom Storage 存儲機制

DOM 存儲是一套在 Web Applications 1.0 規範中首次引入的與存儲相關的特性的總稱,現在已經分離出來,單獨發展成為獨立的 W3C Web 存儲規範。 DOM 存儲被設計為用來提供一個更大存儲量、更安全、更便捷的存儲方法,從而可以代替掉將一些不需要讓伺服器知道的信息存儲到 cookies 里的這種傳統方法。

上面一段是對 Dom Storage 存儲機制的官方表述。看起來,Dom Storage 機制類似 Cookies,但有一些優勢。

Dom Storage 是通過存儲字元串的 Key/Value 對來提供的,並提供 5MB (不同瀏覽器可能不同,分 HOST)的存儲空間(Cookies 才 4KB)。另外 Dom Storage 存儲的數據在本地,不像 Cookies,每次請求一次頁面,Cookies 都會發送給伺服器。

DOM Storage 分為 sessionStorage 和 localStorage。localStorage 對象和 sessionStorage 對象使用方法基本相同,它們的區別在於作用的範圍不同。sessionStorage 用來存儲與頁面相關的數據,它在頁面關閉後無法使用。而 localStorage 則持久存在,在頁面關閉後也可以使用。

Dom Storage 提供了以下的存儲介面:

1 2 3 4 5 6 7 8 interface Storage {  readonly attribute unsigned long length;  [IndexGetter] DOMString key(in unsigned long index);  [NameGetter] DOMString getItem(in DOMString key);  [NameSetter] void setItem(in DOMString key, in DOMString data);  [NameDeleter] void removeItem(in DOMString key);  void clear(); };

sessionStorage 是個全局對象,它維護著在頁面會話(page session)期間有效的存儲空間。只要瀏覽器開著,頁面會話周期就會一直持續。當頁面重新載入(reload)或者被恢復(restores)時,頁面會話也是一直存在的。每在新標簽或者新視窗中打開一個新頁面,都會初始化一個新的會話。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  // 當頁面刷新時,從sessionStorage恢復之前輸入的內容  window.onload = function(){     if (window.sessionStorage) {         var name = window.sessionStorage.getItem("name");         if (name != "" || name != null){             document.getElementById("name").value = name;          }      }  };  // 將數據保存到sessionStorage對象中  function saveToStorage() {     if (window.sessionStorage) {         var name = document.getElementById("name").value;         window.sessionStorage.setItem("name", name);         window.location.href="session_storage.html";      }  }

當瀏覽器被意外刷新的時候,一些臨時數據應當被保存和恢復。sessionStorage 對象在處理這種情況的時候是最有用的。比如恢復我們在表單中已經填寫的數據。

把上面的代碼複製到 session_storage.html(也可以從附件中直接下載)頁面中,用 Google Chrome 瀏覽器的不同 PAGE 或 WINDOW 打開,在輸入框中分別輸入不同的文字,再點擊“Save”,然後分別刷新。每個 PAGE 或 WINDOW 顯示都是當前PAGE輸入的內容,互不影響。關閉 PAGE,再重新打開,上一次輸入保存的內容已經沒有了。

F3p7KoF.gif

FTSyNzK.gif

Local Storage 的介面、用法與 Session Storage 一樣,唯一不同的是:Local Storage 保存的數據是持久性的。當前 PAGE 關閉(Page Session 結束後),保存的數據依然存在。重新打開PAGE,上次保存的數據可以獲取到。另外,Local Storage 是全局性的,同時打開兩個 PAGE 會共用一份存數據,在一個PAGE中修改數據,另一個 PAGE 中是可以感知到的。

1 2 3 4 5 6 7 8   //通過localStorage直接引用key, 另一種寫法,等價於:   //localStorage.getItem("pageLoadCount");   //localStorage.setItem("pageLoadCount", value);   if (!localStorage.pageLoadCount) localStorage.pageLoadCount = 0;      localStorage.pageLoadCount = parseInt(localStorage.pageLoadCount) + 1;      document.getElementById('count').textContent = localStorage.pageLoadCount;    You have viewed this page     an untold number of    time(s).

將上面代碼複製到 local_storage.html 的頁面中,用瀏覽器打開,pageLoadCount 的值是1;關閉 PAGE 重新打開,pageLoadCount 的值是2。這是因為第一次的值已經保存了。

gX0nhDe.gif

VsSJUCN.gif

用兩個 PAGE 同時打開 local_storage.html,並分別交替刷新,發現兩個 PAGE 是共用一個 pageLoadCount 的。

K3d9gc0.gif

cWePbMp.gif

分析:Dom Storage 給 Web 提供了一種更錄活的數據存儲方式,存儲空間更大(相對 Cookies),用法也比較簡單,方便存儲伺服器或本地的一些臨時數據。

從 DomStorage 提供的介面來看,DomStorage 適合存儲比較簡單的數據,如果要存儲結構化的數據,可能要藉助 JASON了,將要存儲的對象轉為 JASON 字串。不太適合存儲比較複雜或存儲空間要求比較大的數據,也不適合存儲靜態的文件等。

在 Android 內嵌 Webview 中,需要通過 Webview 設置介面啟用 Dom Storage。

1 2 3 WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setDomStorageEnabled(true);

拿 Android 類比的話,Web 的 Dom Storage 機制類似於 Android 的 SharedPreference 機制。

2.3 Web SQL Database存儲機制

H5 也提供基於 SQL 的資料庫存儲機制,用於存儲適合資料庫的結構化數據。根據官方的標準文檔,Web SQL Database 存儲機制不再推薦使用,將來也不再維護,而是推薦使用 AppCache 和 IndexedDB。

現在主流的瀏覽器(點擊查看瀏覽器支持情況)都還是支持 Web SQL Database 存儲機制的。Web SQL Database 存儲機制提供了一組 API 供 Web App 創建、存儲、查詢資料庫。

下麵通過簡單的例子,演示下 Web SQL Database 的使用。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20     if(window.openDatabase){       //打開資料庫,如果沒有則創建       var db = openDatabase('mydb''1.0''Test DB', 2 * 1024);        //通過事務,創建一個表,並添加兩條記錄       db.transaction(function (tx) {            tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');            tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');            tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');        });       //查詢表中所有記錄,並展示出來      db.transaction(function (tx) {          tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {              var len = results.rows.length, i;              msg = "Found rows: " + len + "";              for(i=0; i" + results.rows.item(i).log + "";              }              document.querySelector('#status').innerHTML =  msg;              }, null);       }); }Status Message

將上面代碼複製到 sql_database.html 中,用瀏覽器打開,可看到下麵的內容。

ZSA5PB2.gif

官方建議瀏覽器在實現時,對每個 HOST 的資料庫存儲空間作一定限制,建議預設是 5MB(分 HOST)的配額;達到上限後,可以申請更多存儲空間。另外,現在主流瀏覽器 SQL Database 的實現都是基於 SQLite。

分析:SQL Database 的主要優勢在於能夠存儲結構複雜的數據,能充分利用資料庫的優勢,可方便對數據進行增加、刪除、修改、查詢。由於 SQL 語法的複雜性,使用起來麻煩一些。SQL Database 也不太適合做靜態文件的緩存。

在 Android 內嵌 Webview 中,需要通過 Webview 設置介面啟用 SQL Database,同時還要設置資料庫文件的存儲路徑。

1 2 3 4 5 WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setDatabaseEnabled(true); final String dbPath = getApplicationContext().getDir("db", Context.MODE_PRIVATE).getPath(); webSettings.setDatabasePath(dbPath);

Android 系統也使用了大量的資料庫用來存儲數據,比如聯繫人、短消息等;資料庫的格式也 SQLite。Android 也提供了 API 來操作 SQLite。Web SQL Database 存儲機制就是通過提供一組 API,藉助瀏覽器的實現,將這種 Native 的功能提供給了 Web App。

2.4 Application Cache 機制

Application Cache(簡稱 AppCache)似乎是為支持 Web App 離線使用而開發的緩存機制。它的緩存機制類似於瀏覽器的緩存(Cache-Control 和 Last-Modified)機制,都是以文件為單位進行緩存,且文件有一定更新機制。但 AppCache 是對瀏覽器緩存機制的補充,不是替代。

先拿 W3C 官方的一個例子,說下 AppCache 機制的用法與功能。

1 Get Date and TimeTry opening this page, then go offline, and reload the page. The script and the image should still work.

上面 HTML 文檔,引用外部一個 JS 文件和一個 GIF 圖片文件,在其 HTML 頭中通過 manifest 屬性引用了一個 appcache 結尾的文件。

我們在 Google Chrome 瀏覽器中打開這個 HTML 鏈接,JS 功能正常,圖片也顯示正常。禁用網路,關閉瀏覽器重新打開這個鏈接,發現 JS 工作正常,圖片也顯示正常。當然也有可能是瀏覽緩存起的作用,我們可以在文件的瀏覽器緩存過期後,禁用網路再試,發現 HTML 頁面也是正常的。

通過 Google Chrome 瀏覽器自帶的工具,我們可以查看已經緩存的 AppCache(分 HOST)。

hq9dR63.gif

上面截圖中的緩存,就是我們剛纔打開 HTML 的頁面 AppCache。從截圖中看,HTML 頁面及 HTML 引用的 JS、GIF 圖像文件都被緩存了;另外 HTML 頭中 manifest 屬性引用的 appcache 文件也緩存了。

AppCache 的原理有兩個關鍵點:manifest 屬性和 manifest 文件。

HTML 在頭中通過 manifest 屬性引用 manifest 文件。manifest 文件,就是上面以 appcache 結尾的文件,是一個普通文件文件,列出了需要緩存的文件。

bMFTDmR.gif

上面截圖中的 manifest 文件,就 HTML 代碼引用的 manifest 文件。文件比較簡單,第一行是關鍵字,第二、三行就是要緩存的文件路徑(相對路徑)。這隻是最簡單的 manifest 文件,完整的還包括其他關鍵字與內容。引用 manifest 文件的 HTML 和 manifest 文件中列出的要緩存的文件最終都會被瀏覽器緩存。

完整的 manifest 文件,包括三個 Section,類型 Windows 中 ini 配置文件的 Section,不過不要中括弧。

  1. CACHE MANIFEST - Files listed under this header will be cached after they are downloaded for the first time

  2. NETWORK - Files listed under this header require a connection to the server, and will never be cached

  3. FALLBACK - Files listed under this header specifies fallback pages if a page is inaccessible

完整的 manifest 文件,如:

1 2 3 4 5 6 7 8 9 CACHE MANIFEST # 2012-02-21 v1.0.0 /theme.css /logo.gif /main.js NETWORK: login.asp FALLBACK: /html/ /offline.html

總的來說,瀏覽器在首次載入 HTML 文件時,會解析 manifest 屬性,並讀取 manifest 文件,獲取 Section:CACHE MANIFEST 下要緩存的文件列表,再對文件緩存。

AppCache 的緩存文件,與瀏覽器的緩存文件分開存儲的,還是一份?應該是分開的。因為 AppCache 在本地也有 5MB(分 HOST)的空間限制。

AppCache 在首次載入生成後,也有更新機制。被緩存的文件如果要更新,需要更新 manifest 文件。因為瀏覽器在下次載入時,除了會預設使用緩存外,還會在後臺檢查 manifest 文件有沒有修改(byte by byte)。發現有修改,就會重新獲取 manifest 文件,對 Section:CACHE MANIFEST 下文件列表檢查更新。manifest 文件與緩存文件的檢查更新也遵守瀏覽器緩存機制。

如用用戶手動清了 AppCache 緩存,下次載入時,瀏覽器會重新生成緩存,也可算是一種緩存的更新。另外, Web App 也可用代碼實現緩存更新。

分析:AppCache 看起來是一種比較好的緩存方法,除了緩存靜態資源文件外,也適合構建 Web 離線 App。在實際使用中有些需要註意的地方,有一些可以說是”坑“。

  1. 要更新緩存的文件,需要更新包含它的 manifest 文件,那怕只加一個空格。常用的方法,是修改 manifest 文件註釋中的版本號。如:# 2012-02-21 v1.0.0

  2. 被緩存的文件,瀏覽器是先使用,再通過檢查 manifest 文件是否有更新來更新緩存文件。這樣緩存文件可能用的不是最新的版本。

  3. 在更新緩存過程中,如果有一個文件更新失敗,則整個更新會失敗。

  4. manifest 和引用它的HTML要在相同 HOST。

  5. manifest 文件中的文件列表,如果是相對路徑,則是相對 manifest 文件的相對路徑。

  6. manifest 也有可能更新出錯,導致緩存文件更新失敗。

  7. 沒有緩存的資源在已經緩存的 HTML 中不能載入,即使有網路。例如:http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/

  8. manifest 文件本身不能被緩存,且 manifest 文件的更新使用的是瀏覽器緩存機制。所以 manifest 文件的 Cache-Control 緩存時間不能設置太長。

另外,根據官方文檔,AppCache 已經不推薦使用了,標準也不會再支持。現在主流的瀏覽器都是還支持 AppCache的,以後就不太確定了。

在Android 內嵌 Webview中,需要通過 Webview 設置介面啟用 AppCache,同時還要設置緩存文件的存儲路徑,另外還可以設置緩存的空間大小。

1 2 3 4 5 6 WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setAppCacheEnabled(true); final String cachePath = getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath(); webSettings.setAppCachePath(cachePath); webSettings.setAppCacheMaxSize(5*1024*1024);

2.5 Indexed Database

IndexedDB 也是一種資料庫的存儲機制,但不同於已經不再支持的 Web SQL Database。IndexedDB 不是傳統的關係資料庫,可歸為 NoSQL 資料庫。IndexedDB 又類似於 Dom Storage 的 key-value 的存儲方式,但功能更強大,且存儲空間更大。

IndexedDB 存儲數據是 key-value 的形式。Key 是必需,且要唯一;Key 可以自己定義,也可由系統自動生成。Value 也是必需的,但 Value 非常靈活,可以是任何類型的對象。一般 Value 都是通過 Key 來存取的。

IndexedDB 提供了一組 API,可以進行數據存、取以及遍歷。這些 API 都是非同步的,操作的結果都是在回調中返回。

下麵代碼演示了 IndexedDB 中 DB 的打開(創建)、存儲對象(可理解成有關係數據的”表“)的創建及數據存取、遍歷基本功能。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 var db; window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //瀏覽器是否支持IndexedDB if (window.indexedDB) {    //打開資料庫,如果沒有,則創建    var openRequest = window.indexedDB.open("people_db", 1);    //DB版本設置或升級時回調    openRequest.onupgradeneeded = function(e) {        console.log("Upgrading...");        var thisDB = e.target.result;        if(!thisDB.objectStoreNames.contains("people")) {            console.log("Create Object Store: people.");            //創建存儲對象,類似於關係資料庫的表            thisDB.createObjectStore("people", { autoIncrement:true });           //創建存儲對象, 還創建索引           //var objectStore = thisDB.createObjectStore("people",{ autoIncrement:true });          // //first arg is name of index, second is the path (col);         //objectStore.createIndex("name","name", {unique:false});        //objectStore.createIndex("email","email", {unique:true});      } } //DB成功打開回調 openRequest.onsuccess = function(e) {     console.log("Success!");     //保存全局的資料庫對象,後面會用到     db = e.target.result;    //綁定按鈕點擊事件      document.querySelector("#addButton").addEventListener("click", addPerson, false);     document.querySelector("#getButton").addEventListener("click", getPerson, false);     document.querySelector("#getAllButton").addEventListener("click", getPeople, false);     document.querySelector("#getByName").addEventListener("click", getPeopleByNameIndex1, false); }   //DB打開失敗回調   openRequest.onerror = function(e) {       console.log("Error");       console.dir(e);    } }else{     alert('Sorry! Your browser doesn\'t support the IndexedDB.'); } //添加一條記錄 function addPerson(e) {     var name = document.querySelector("#name").value;     var email = document.querySelector("#email").value;     console.log("About to add "+name+"/"+email);     var transaction = db.transaction(["people"],"readwrite"); var store = transaction.objectStore("people");    //Define a person    var person = {        name:name,        email:email,        created:new Date()    }    //Perform the add    var request = store.add(person);    //var request = store.put(person, 2);    request.onerror = function(e) {        console.log("Error",e.target.error.name);        //some type of error handler    }    request.onsuccess = function(e) {       console.log("Woot! Did it.");    } } //通過KEY查詢記錄 function getPerson(e) {     var key = document.querySelector("#key").value;     if(key === "" || isNaN(key)) return;
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說明:信息系統實踐手記系列是系筆者在平時研發中先後遇到的大小的問題,也許朴實和細微,但往往卻是經常遇到的問題。筆者對其中比較典型的加以收集,描述,歸納和分享。 摘要:介紹典型的客戶端中列表數據展現的6個要素。 正文 1.客戶端和伺服器 一般典型的信息系統總可以分為前臺(也稱“客戶端”)和後臺(也稱“
  • 這篇文章主要寫給我們這些非電腦專業的又要寫程式、實現演算法的人,有的連多線程都不會,所以這裡就說些不需要大篇幅修改程式就可以簡單實現的並行計算。 這邊把並行計算分為2類,基於CPU的多線程處理、基於異構架構的並行計算(如GPU等)。基於CPU的主要有:OpenMP、TBB、PPL、Parallel、
  • 1 package com.shejimoshi.structural.Proxy; 2 3 4 /** 5 * 功能:為其他對象提供一種代理以控制這個對象的訪問 6 * 適用:1、遠程代理,為一個對象在不同的地址空間提供局部代表 7 * 2、虛代理,根據需要創建開銷很大的對象 8 * 3、保護代理
  • CCS3屬性之text-overflow:ellipsis;的用法和註意之處 語法: text-overflow:clip | ellipsis 預設值:clip 適用於:所有元素 clip: 當對象內文本溢出時不顯示省略標記(...),而是將溢出的部分裁切掉。 ellipsis: 當對象內文本溢出
  • JavaScript 中的所有事物都是對象:字元串、數字、數組、日期,等等。 在 JavaScript 中,對象是擁有屬性和方法的數據。 屬性和方法 屬性是與對象相關的值。 方法是能夠在對象上執行的動作。 舉例:汽車就是現實生活中的對象。 汽車的屬性: car.name=Fiat car.model
  • forEach是ECMA5中Array新方法中最基本的一個,就是遍歷,迴圈。例如下麵這個例子: [1, 2 ,3, 4].forEach(alert); 等同於下麵這個for迴圈 var array = [1, 2, 3, 4]; for (var k = 0, length = array.len
  • 在編寫CSS時也存在一些編碼規範,平時註意這些基本的規範,可使代碼更易閱讀和維護。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> /* 語法 用兩個空格來代替製表符(tab
  • 在編寫HTML時,可能有一些方面不夠規範,在通過對《HTML5編碼規範》的學習後,採用代碼註解的方式,做相關的整理,方便今後回顧。 1 <!DOCTYPE html> <!-- HTML5 doctype 標準模式(standard mode)的聲明,這樣能夠確保在每個瀏覽器中擁有一致的展現-->
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...