瀏覽器客戶端存儲(chǔ)技術(shù)

客戶端存儲(chǔ)技術(shù)

介紹瀏覽器的客戶端存儲(chǔ)技術(shù),包括:Cookie、Storage、IndexedDB、Application Cache和已經(jīng)過(guò)時(shí)但還是很常見(jiàn)的Web SQL,以及一些其他的還未普及的存儲(chǔ)技術(shù):Cache Storage、FileSystem API。

Cookie

特點(diǎn):

  • 具有大小限制,4~8k
  • 綁定到域名,對(duì)同一個(gè)域名的請(qǐng)求會(huì)自動(dòng)帶上cookie請(qǐng)求頭
  • 能夠給cookie設(shè)置有效時(shí)間

cookie使用key=value的形式記錄用戶信息,多個(gè)鍵值對(duì)之間使用;分隔

前端通過(guò)操縱document下的cookie屬性直接操縱cookie

document.cookie
//"irstime=1492081681236; uuid_tt_dd=242117069142"

與cookie相關(guān)的請(qǐng)求頭有兩個(gè),一個(gè)是Set-Cookie(用在響應(yīng)中,用于設(shè)置cookie和附加信息。一個(gè)Set-Cookie可以設(shè)置一對(duì)或多對(duì)鍵值對(duì)),一個(gè)是Cookie(用在請(qǐng)求時(shí),表示發(fā)送的cookie)

Set-Cookie格式

 Set-Cookie: <name>=<value>[; <name>=<value>]...
        [; expires=<date>][; domain=<domain_name>]
        [; path=<some_path>][; secure][; httponly]

Storage

Storage分為本地存儲(chǔ)(Local Storage)和會(huì)話存儲(chǔ)(Session Storage)。兩者使 用完全相同的API,但本地存儲(chǔ)會(huì)持久存在(或者直到用戶清除),而會(huì)話存儲(chǔ)只要瀏覽器 關(guān)閉就會(huì)消失。存儲(chǔ)的鍵值只能為字符串,storage存儲(chǔ)的鍵值也是和域名相掛鉤的。

API
localStorge.setItem:設(shè)置特定鍵值;
localStorge.getItem:檢索特定的鍵值;
localStorge.removeItem:刪除鍵值及其相關(guān)聯(lián)的值;
localStorge.clear:刪除所有的鍵值(只限定于發(fā)出請(qǐng)求的特定域名)

IndexedDB

IndexedDB 數(shù)據(jù)庫(kù)使用key-value鍵值對(duì)儲(chǔ)存數(shù)據(jù),IndexedDB 是事務(wù)模式的數(shù)據(jù)庫(kù)(任何操作都發(fā)生在事務(wù)中),API 基本上是異步的(使用事件模型)。

IndexedDB是一個(gè)基于JavaScript的面向?qū)ο蟮臄?shù)據(jù)庫(kù)。
允許存儲(chǔ)和檢索用鍵索引的對(duì)象; 可以存儲(chǔ)結(jié)構(gòu)化克隆算法支持的任何對(duì)象;IndexedDB也遵循同源策略。

結(jié)構(gòu)化克隆支持的對(duì)象:RegExp、Blob、File、Filelist、ImageData、CanvasPixelArray(克隆力度將會(huì)跟原始對(duì)象相同)、可以正確復(fù)制有循環(huán)引用的對(duì)象。

不支持的對(duì)象:

  • Error、Function、DOM節(jié)點(diǎn)
  • 對(duì)象的某些特定參數(shù)也不會(huì)被保留
    • RegExp 對(duì)象的 lastIndex 字段不會(huì)被保留
    • 屬性描述符,setters 以及 getters(以及其他類似元數(shù)據(jù)的功能)同樣不會(huì)被復(fù)制。例如,如果一個(gè)對(duì)象用屬性描述符標(biāo)記為 read-only,它將會(huì)被復(fù)制為 read-write,因?yàn)檫@是默認(rèn)的情況下。
    • 原形鏈上的屬性也不會(huì)被追蹤以及復(fù)制。

初始化數(shù)據(jù)庫(kù)

var localDatabase = {};

localDatabase.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
localDatabase.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;

var DB = "db_user",VERSION = 1.0;

/*打開(kāi)數(shù)據(jù)庫(kù)*/
function openDB(dbName, version, objStore, columnArr) {
    var db = localDatabase.db;
    try {
        if (db) db.close();
        version = version || 1;
        // 打開(kāi)數(shù)據(jù)庫(kù)
        var openRequest = localDatabase.indexedDB.open(dbName, version);
        // 成功打開(kāi)數(shù)據(jù)庫(kù)
        openRequest.onsuccess = function() {
            localDatabase.db = openRequest.result;
        };
        // 創(chuàng)建或刪除存儲(chǔ)對(duì)象只能在此進(jìn)行
        openRequest.onupgradeneeded = function(e) {
            var db = e.currentTarget.result;
            if (!db.objectStoreNames.contains(objStore)) {
                //創(chuàng)建存儲(chǔ)對(duì)象并設(shè)置主鍵
                var store = db.createObjectStore(objStore, {
                    keyPath: "id"
                });
                // 創(chuàng)建索引,方便根據(jù)字段進(jìn)行搜索
                for (var i = 0, len = columnArr.length; i < len; i++) {
                    store.createIndex(columnArr[i], columnArr[i], {
                        unique: false
                    });
                }
                console.log("創(chuàng)建存儲(chǔ)對(duì)象成功")
            }
        };
        openRequest.onerror = function(e){
            console.error(e.message);
        };
    } catch (e) {
        console.error(e.message);
    }
}

插入和刪除數(shù)據(jù)

/*添加數(shù)據(jù)*/
var request = localDatabase.db.transaction(objStore, "readwrite").objectStore(objStore).add(obj);
request.onsuccess = function(event) {
  // 添加成功!
};

/*刪除數(shù)據(jù)*/
var request = db.transaction(["customers"], "readwrite").objectStore("customers").delete("444-44-4444");
request.onsuccess = function(event) {
  // 刪除數(shù)據(jù)成功!
};

使用索引獲取單個(gè)值,使用游標(biāo)獲取多個(gè)值

/*使用索引獲取單個(gè)值*/
var transaction = db.transaction(objStore),
    store = transaction.objectStore(objStore),
    request = store.get(key);

request.onsuccess = function(evt) {
    console.log(JSON.stringify(evt.target.result));
};

/* 使用游標(biāo)獲取多個(gè)值 */
var recordArr = [];

function queryAllRecords(objStore) {
    recordArr = [];
    var db = localDatabase.db;
    try {
        var transaction = db.transaction(objStore),
            store = transaction.objectStore(objStore),
            request = store.openCursor();

        request.onsuccess = function(evt) {
            var cursor = evt.target.result,
                jsonStr = "";
            if (cursor) {
                var records = cursor.value;
                jsonStr = jsonStr + JSON.stringify(records);
                console.log(jsonStr);
                recordArr.push(records);
                cursor.continue();
            }
        };
    } catch (e) {
        console.error(e.message);
    }
}

更多IDB代碼見(jiàn):IDB_Util

Application Cache

Application Cache使用的是一套緩存列表。所謂列表,只是一個(gè)非常簡(jiǎn)單的文本文檔,其中列舉了所有應(yīng)該或不應(yīng)該通過(guò)緩存機(jī)制處理的資源條目,從而指導(dǎo)瀏覽器下載特定文件、加以保存并在必要時(shí)予以使用——而不必再向服務(wù)器發(fā)出重復(fù)請(qǐng)求。

要使用Application Cache,我們需要首先在包含有緩存對(duì)象文件的網(wǎng)站中保存一個(gè)擴(kuò)展名為.appcache的文本文件。根據(jù)所使用Web服務(wù)器的具體類型,我們可能需要為.appcache文件創(chuàng)建一個(gè)自定義MIME類型以確保它們能夠正確作用于瀏覽器并可被作為應(yīng)用程序緩存文件讀取。

例如:

CACHE MANIFEST
# 以上折行必需要寫

CACHE:
# 這部分寫需要緩存的資源文件列表
# 可以是相對(duì)路徑也可以是絕對(duì)路徑
index.html
index.css
images/logo.png
js/main.js
http://img.baidu.com/js/tangram-base-1.5.2.1.js

NETWORK:
# 可選
# 這一部分是要繞過(guò)緩存直接讀取的文件
login.php


FALLBACK:
# 可選
# 這部分寫當(dāng)訪問(wèn)緩存失敗后,備用訪問(wèn)的資源
# 每行兩個(gè)文件,第一個(gè)是訪問(wèn)源,第二個(gè)是替換文件*.html /offline.html 

html文件中的設(shè)置

<html manifest="demo.cache">
</html>

apache服務(wù)器中,定義
tAddType text/cache-manifest .cache

緩存更新

更新manifest文件
  瀏覽器發(fā)現(xiàn)manifest文件本身發(fā)生變化,便會(huì)根據(jù)新的manifest文件去獲取新的資源進(jìn)行緩存。
  當(dāng)manifest文件列表并沒(méi)有變化的時(shí)候,我們通常通過(guò)修改manifest注釋的方式來(lái)改變文件,從而實(shí)現(xiàn)更新。

使用js的方式

var appCache = window.applicationCache;

appCache.update(); //嘗試更新緩存


if (appCache.status == window.applicationCache.UPDATEREADY) {
  appCache.swapCache();  //更新成功后,切換到新的緩存
}

Web SQL

web sql的規(guī)范工作已經(jīng)被W3C停止,按照官方的說(shuō)法是web sql后臺(tái)使用的都是SQLite,但為了實(shí)現(xiàn)規(guī)范前臺(tái)會(huì)有許多不同的實(shí)現(xiàn)。因此規(guī)范被停止。但是仍然有許多老系統(tǒng)、插件使用web sql,因此學(xué)習(xí)web sql對(duì)我們還是有著不小的好處。

Web SQL Database 規(guī)范中定義了三個(gè)核心方法:

  • openDatabase:這個(gè)方法使用現(xiàn)有數(shù)據(jù)庫(kù)或新建數(shù)據(jù)庫(kù)來(lái)創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象
  • transaction:這個(gè)方法允許我們根據(jù)情況控制事務(wù)提交或回滾
  • executeSql:這個(gè)方法用于執(zhí)行SQL 查詢

openDatabase

var db = openDatabase(dbName, dbVersion, showName, size,callback);

db.transaction(function(context) {
    context.executeSql('CREATE TABLE IF NOT EXISTS testTable (id unique, name)');
    context.executeSql('INSERT INTO testTable (id, name) VALUES (0, "Byron")');
    context.executeSql('INSERT INTO testTable (id, name) VALUES (1, "Casper")');
    context.executeSql('INSERT INTO testTable (id, name) VALUES (2, "Frank")');
    context.executeSql('SELECT * FROM testTable where id=? and name=?', [2, 'Frank'], function(context, results) {
        var len = results.rows.length, i;
        console.log('Got ' + len + ' rows.');
        for (i = 0; i < len; i++) {
            console.log('id: ' + results.rows.item(i).id);
            console.log('name: ' + results.rows.item(i).name);
        }
    }, errorCallback);
}, successCallback, errorCallback);

其他

Cache Storage

Cache Storage用來(lái)存儲(chǔ) Response 對(duì)象的。也就是說(shuō)用來(lái)對(duì) HTTP ,響應(yīng)做緩存的。CacheStorage 在瀏覽器上的引用名叫 caches ,它定義在 ServiceWorker 的規(guī)范中。CacheStorage 是多個(gè) Cache 的集合,而每個(gè) Cache 可以存儲(chǔ)多個(gè) Response 對(duì)象。CacheStorage的設(shè)計(jì)風(fēng)格也和ServiceWork一樣都基于Promise。

  • match() 返回promise,resolve為response對(duì)象,如果在任意一個(gè)cache中找到與key對(duì)應(yīng)的響應(yīng)對(duì)象
  • has() 返回promise對(duì)象,resolve為boolean,根據(jù)是否含有記錄,得到不同的值
  • open() 返回promise,resolve為cache,如果不存在對(duì)應(yīng)的cache,則新建一個(gè)
  • delete() 返回promise,resolve為boolean,如果刪除cache成功則為true
  • keys() 返回promise,resolve為cache數(shù)組

使用cache storage與service worker建立離線應(yīng)用

在頁(yè)面腳本中添加如下代碼

//注冊(cè)一個(gè)serviceWorker
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw-demo-cache.js');
}

在sw-demo-cache.js中添加如下代碼

// sw-demo-cache.js
var VERSION = 'v1';

// 緩存
self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(VERSION).then(function(cache) {
        //需要做緩存的文件
      return cache.addAll([
        './start.html',
        './static/jquery.min.js',
        './static/mm1.jpg'
      ]);
    })
  );
});

// 緩存更新
self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          // 如果當(dāng)前版本和緩存版本不一致
          if (cacheName !== VERSION) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

// 捕獲請(qǐng)求并返回緩存數(shù)據(jù)
self.addEventListener('fetch', function(event) {
  event.respondWith(caches.match(event.request).catch(function() {
    return fetch(event.request);
  }).then(function(response) {
    caches.open(VERSION).then(function(cache) {
      cache.put(event.request, response);
    });
    return response.clone();
  }).catch(function() {
    //沒(méi)法從緩存和請(qǐng)求中得到資源時(shí)的處理辦法
    return caches.match('./static/mm1.jpg');
  }));
});

FileSystem API

使用 FileSystem API,網(wǎng)絡(luò)應(yīng)用就可以創(chuàng)建、讀取、導(dǎo)航用戶本地文件系統(tǒng)中的沙盒部分以及向其中寫入數(shù)據(jù)。但是目前FileSystem API并不普及,支持的只有chrome瀏覽器。FileSystem API提供了文件系統(tǒng)的管理、文件/目錄的管理、文件的管理等API。剛興趣的朋友可以閱讀探索FileSystem API

參考文獻(xiàn)

IndexedDB
使用IndexedDB
application cache api
Web SQL Database
CacheStorage 緩存存儲(chǔ)
借助Service Worker和cacheStorage緩存及離線開(kāi)發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:H5緩存機(jī)制淺析-移動(dòng)端Web加載性能優(yōu)化【干貨】 作者:賀輝超,騰訊游戲平臺(tái)與社區(qū)產(chǎn)品部 高級(jí)工程師 目錄...
    meng_philip123閱讀 11,688評(píng)論 6 48
  • 本文介紹本地?cái)?shù)據(jù)存儲(chǔ)的選型。簡(jiǎn)單總結(jié)一些查詢到的關(guān)于本地?cái)?shù)據(jù)存儲(chǔ)的技術(shù)。 控制臺(tái)展示前端存儲(chǔ) Chrome: 前端...
    謝大見(jiàn)閱讀 9,294評(píng)論 1 8
  • 瀏覽器緩存(Browser Caching)是瀏覽器端保存數(shù)據(jù)用于快速讀取或避免重復(fù)資源請(qǐng)求的優(yōu)化機(jī)制,有效的緩存...
    fuyou2324閱讀 5,292評(píng)論 0 8
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評(píng)論 19 139
  • 考試結(jié)束了 考試結(jié)束了,衛(wèi)藍(lán)一個(gè)人走在回家的路上,任寒風(fēng)蹂躪著自己的面龐。他不時(shí)從口中吐出熱氣,樹(shù)脂鏡片上蒙上了一...
    不愛(ài)讀書(shū)的一天閱讀 279評(píng)論 0 1

友情鏈接更多精彩內(nèi)容