自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊一聊常見的瀏覽器數(shù)據(jù)存儲方案

系統(tǒng) 瀏覽器
無論哪種方式,將這些信息保存在客戶端可以減少額外且不必要的服務(wù)器調(diào)用,并幫助提供離線支持。不過,需要注意,由于實(shí)現(xiàn)差異,瀏覽器存儲機(jī)制在不同瀏覽器中的行為可能會有所不同。除此之外,許多瀏覽器已刪除對 Web SQL 的支持,建議將現(xiàn)有用法遷移到 IndexedDB。

大家好,CUGGZ。

今天來分享常見的瀏覽器數(shù)據(jù)存儲方案:localStorage、sessionStorage、IndexedDB、Cookies。

1. 概述

現(xiàn)代瀏覽器中提供了多種存儲機(jī)制,打開瀏覽器的控制臺(Mac 可以使用 Command + Option + J 快捷鍵,Windows  可以使用 Control + Shift + J 快捷鍵)。選擇 Application 選項(xiàng)卡,可以在 Storage中 看到 Local Storage、Session Storage、IndexedDB、Web SQL、Cookies 等:

圖片

那數(shù)據(jù)存儲在瀏覽器中有什么使用場景呢?在以下情況下,將數(shù)據(jù)存儲在瀏覽器中成為更可行的選擇:

  • 在瀏覽器存儲中保存應(yīng)用狀態(tài),比如保持用戶偏好(用戶特定的設(shè)置,例如亮模式或暗模式、字體大小等);
  • 創(chuàng)建離線工作的漸進(jìn)式 Web 應(yīng)用,除了初始下載和更新之外沒有服務(wù)器端要求;
  • 緩存靜態(tài)應(yīng)用資源,如 HTML、CSS、JS 和圖像等;
  • 保存上一個瀏覽會話中的數(shù)據(jù),例如存儲上一個會話中的購物車內(nèi)容,待辦事項(xiàng)列表中的項(xiàng)目,記住用戶是否以前登錄過等。

無論哪種方式,將這些信息保存在客戶端可以減少額外且不必要的服務(wù)器調(diào)用,并幫助提供離線支持。不過,需要注意,由于實(shí)現(xiàn)差異,瀏覽器存儲機(jī)制在不同瀏覽器中的行為可能會有所不同。除此之外,許多瀏覽器已刪除對 Web SQL 的支持,建議將現(xiàn)有用法遷移到 IndexedDB。

所以下面我們將介紹 Local Storage、Session Storage、IndexedDB、Cookies 的使用方式、使用場景以及它們之間的區(qū)別。

2. Web Storage

(1)概述

HTML5 引入了 Web Storage,這使得在瀏覽器中存儲和檢索數(shù)據(jù)變得更加容易。Web Storage API 為客戶端瀏覽器提供了安全存儲和輕松訪問鍵值對的機(jī)制。Web Storage 提供了兩個 API 來獲取和設(shè)置純字符串的鍵值對:

  • localStorage:用于存儲持久數(shù)據(jù),除非用戶手動將其從瀏覽器中刪除,否則數(shù)據(jù)將終身存儲。即使用戶關(guān)閉窗口或選項(xiàng)卡,它也不會過期;
  • sessionStorage:用于存儲臨時會話數(shù)據(jù),頁面重新加載后仍然存在,關(guān)閉瀏覽器選項(xiàng)卡時數(shù)據(jù)丟失。

(2)方法和屬性

Web Storage API 由 4 個方法 setItem()、getItem()、removeItem() 、clear()、key()和一個 length 屬性組成,以 localStorage 為例:

  • setItem()? :用于存儲數(shù)據(jù),它有兩個參數(shù),即key和value?。使用形式:localStorage.setItem(key, value);
  • getItem()?:用于檢索數(shù)據(jù),它接受一個參數(shù) key,即需要訪問其值的鍵。使用形式:localStorage.getItem(key);
  • removeItem()?:用于刪除數(shù)據(jù),它接受一個參數(shù) key,即需要刪除其值的鍵。使用形式:localStorage.removeItem(key);
  • clear()? :用于清除其中存儲的所有數(shù)據(jù),使用形式:localStorage.clear();
  • key():該方法用于獲取 localStorage 中數(shù)據(jù)的所有key,它接受一個數(shù)字作為參數(shù),該數(shù)字可以是 localStorage 項(xiàng)的索引位置。

console.log(typeof window.localStorage) // Object

// 存儲數(shù)據(jù)
localStorage.setItem("colorMode", "dark")
localStorage.setItem("username", "zhangsan")
localStorage.setItem("favColor", "green")

console.log(localStorage.length) // 3

// 檢索數(shù)據(jù)
console.log(localStorage.getItem("colorMode")) // dark

// 移除數(shù)據(jù)
localStorage.removeItem("colorMode")
console.log(localStorage.length) // 2
console.log(localStorage.getItem("colorMode")) // null

// 檢索鍵名
window.localStorage.key(0); // favColor

// 清空本地存儲
localStorage.clear()
console.log(localStorage.length) // 0

localStorage 和 sessionStorage 都非常適合緩存非敏感應(yīng)用數(shù)據(jù)??梢栽谛枰鎯ι倭亢唵沃挡⒉唤?jīng)常訪問它們是使用它們。它們本質(zhì)上都是同步的,并且會阻塞主 UI 線程,所以應(yīng)該謹(jǐn)慎使用。

(3)存儲事件

我們可以在瀏覽器上監(jiān)聽 localStorage 和 sessionStorage 的存儲變化。storage 事件在創(chuàng)建、刪除或更新項(xiàng)目時觸發(fā)。偵聽器函數(shù)在事件中傳遞,具有以下屬性:

  • newValue:當(dāng)在存儲中創(chuàng)建或更新項(xiàng)目時傳遞給 setItem() 的值。當(dāng)從存儲中刪除項(xiàng)目時,此值設(shè)置為 null。
  • oldValue:創(chuàng)建新項(xiàng)目時,如果該鍵存在于存儲中,則該項(xiàng)目的先前的值。
  • key:正在更改的項(xiàng)目的鍵,如果調(diào)用 .clear(),則值為 null。
  • url:執(zhí)行存儲操作的 URL。
  • storageArea:執(zhí)行操作的存儲對象(localStorage 或 sessionStorage)。

通常,我們可以使用 window.addEventListener("storage", func) 或使用 onstorage 屬性(如 window.onstorage = func)來監(jiān)聽 storage 事件:

window.addEventListener('storage', e => {
console.log(e.key);
console.log(e.oldValu);
console.log(e.newValue);
});

window.onstorage = e {
console.log(e.key);
console.log(e.oldValu);
console.log(e.newValue);
});

注意,該功能不會在發(fā)生更改的同一瀏覽器選項(xiàng)卡上觸發(fā),而是由同一域的其他打開的選項(xiàng)卡或窗口觸發(fā)。此功能用于同步同一域的所有瀏覽器選項(xiàng)卡/窗口上的數(shù)據(jù)。因此,要對此進(jìn)行測試,需要打開同一域的另一個選項(xiàng)卡。

(4)存儲限制

localStorage 和 sessionStorage 只能存儲 5 MB 的數(shù)據(jù),因此需要確保存儲的數(shù)據(jù)不會超過此限制。

localStorage.setItem('a', Array(1024 * 1024 * 5).join('a'))
localStorage.setItem('b', 'a')

// Uncaught DOMException: Failed to execute 'setItem' on 'Storage':

在上面的例子中,收到了一個錯誤,首先創(chuàng)建了一個5MB的大字符串,當(dāng)再添加其他數(shù)據(jù)時就報(bào)錯了。

另外,localStorage 和 sessionStorage 只接受字符串??梢酝ㄟ^ JSON.stringify 和 JSON.parse 來解決這個問題:

const user = {
name : "zhangsan",
age : 28,
gender : "male",
profession : "lawyer"
};

localStorage.setItem("user", JSON.stringify(user));
localStorage.getItem("user"); // '{"name":"zhangsan","age":28,"gender":"male","profession":"lawyer"}'
JSON.parse(localStorage.getItem("user")) // {name: 'zhangsan', age: 28, gender: 'male', profession: 'lawyer'}

如果我們直接將一個對象存儲在 localStorage 中,那將會在存儲之前進(jìn)行隱式類型轉(zhuǎn)換,將對象轉(zhuǎn)換為字符串,再進(jìn)行存儲:

const user = {
name : "zhangsan",
age : 28,
gender : "male",
profession : "lawyer"
};

localStorage.setItem("user", user);
localStorage.getItem("user"); // '[object Object]'

Web Storage 使用了同源策略,也就是說,存儲的數(shù)據(jù)只能在同一來源上可用。如果域和子域相同,則可以從不同的選項(xiàng)卡訪問 localStorage 數(shù)據(jù),而無法訪問 sessionStorage 數(shù)據(jù),即使它是完全相同的頁面。

另外:

  • 無法在 web worker 或 service worker 中訪問 Web Storage;
  • 如果瀏覽器設(shè)置為隱私模式,將無法讀取到 Web Storage;
  • Web Storage 很容易被 XSS 攻擊,敏感信息不應(yīng)存儲在本地存儲中;
  • 它是同步的,這意味著所有操作都是一次一個。對于復(fù)雜應(yīng)用,它會減慢應(yīng)用的運(yùn)行時間。

(5)示例

下面來看一個使用 localStorage 的簡單示例,使用 localStorage 來存儲用戶偏好:

<input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
<label for="darkTheme">黑暗模式</label><br>
html {
background: white;
}

.dark {
background: black;
color: white;
}
function toggle(on) {
if (on) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}

function save(on) {
localStorage.setItem('darkTheme', on.toString());
}

function load() {
return localStorage.getItem('darkTheme') === 'true';
}

function onChange(checkbox) {
const value = checkbox.checked;
toggle(value);
save(value);
}

const initialValue = load();
toggle(initialValue);
document.querySelector('#darkTheme').checked = initialValue;

這里的代碼很簡單,頁面上有一個單選框,選中按鈕時將頁面切換為黑暗模式,并將這個配置存儲在 localStorage 中。當(dāng)下一次再初始頁面時,獲取 localStorage 中的主題設(shè)置。

3. Cookie

(1)Cookie 概述

Cookie 主要用于身份驗(yàn)證和用戶數(shù)據(jù)持久性。Cookie 與請求一起發(fā)送到服務(wù)器,并在響應(yīng)時發(fā)送到客戶端;因此,cookies 數(shù)據(jù)在每次請求時都會與服務(wù)器交換。服務(wù)器可以使用 cookie 數(shù)據(jù)向用戶發(fā)送個性化內(nèi)容。嚴(yán)格來說,cookie 并不是客戶端存儲方式,因?yàn)榉?wù)器和瀏覽器都可以修改數(shù)據(jù)。它是唯一可以在一段時間后自動使數(shù)據(jù)過期的方式。

每個 HTTP 請求和響應(yīng)都會發(fā)送 cookie 數(shù)據(jù)。存儲過多的數(shù)據(jù)會使 HTTP 請求更加冗長,從而使應(yīng)用比預(yù)期更慢:

瀏覽器限制 cookie 的大小最大為4kb,特定域允許的 cookie 數(shù)量為 20 個,并且只能包含字符串;

cookie 的操作是同步的;

不能通過 web workers 來訪問,但可以通過全局 window 對象訪問。

Cookie 通常用于會話管理、個性化以及跨網(wǎng)站跟蹤用戶行為。我們可以通過服務(wù)端和客戶端設(shè)置和訪問 cookie。Cookie 還具有各種屬性,這些屬性決定了在何處以及如何訪問和修改它們,

Cookie 分為兩種類型:

會話 Cookie:沒有指定 Expires 或 Max-Age 等屬性,因此在關(guān)閉瀏覽器時會被刪除;

持久性 Cookie:指定 Expires 或 Max-Age 屬性。這些 cookie 在關(guān)閉瀏覽器時不會過期,但會在特定日期 (Expires) 或時間長度 (Max-Age) 后過期。

(2)Cookie 操作

下面先來看看如何訪問和操作客戶端和服務(wù)器上的 cookie。

① 客戶端(瀏覽器)

客戶端 JavaScript 可以通過 document.cookie 來讀取當(dāng)前位置可訪問的所有 cookie。它提供了一個字符串,其中包含一個以分號分隔的 cookie 列表,使用 key=value 格式。

document.cookie;

圖片

可以看到,在語雀主頁中獲取 cookie,結(jié)果中包含了登錄的 cookie、語言、當(dāng)前主題等。

同樣,可以使用 document.cookie 來設(shè)置 cookie 的值,設(shè)置cookie也是用key=value格式的字符串,屬性用分號隔開:

document.cookie = "hello=world; domain=example.com; Secure";

這里用到了兩個屬性 SameSite 和 Secure,下面會介紹。如果已經(jīng)存在同名的 cookie 屬性,就會更新已有的屬性值,如果不存在,就會創(chuàng)建一個新的 key=value。

如果需要經(jīng)常在客戶端處理 Cookie,建議使用像 js-cookie 這樣的庫來處理客戶端 cookie:

Cookies.set('hello', 'world', { domain: 'example.com', secure: true });
Cookies.get('hello'); // -> world

這樣不僅為 cookie 上的 CRUD 操作提供了一個干凈的 API,而且還支持 TypeScript,從而幫助避免屬性的拼寫錯誤。

② 服務(wù)端(Node.js)

服務(wù)端可以通過 HTTP 請求的請求頭和響應(yīng)頭來訪問和修改 cookie。每當(dāng)瀏覽器向服務(wù)端發(fā)送 HTTP 請求時,它都會使用 cookie 頭將所有相關(guān) cookie 都附加到該站點(diǎn)。請求標(biāo)頭是一個分號分隔的字符串。

圖片

這樣就可以從請求頭中讀取這些 cookie。如果在服務(wù)端使用 Node.js,可以像下面這樣從請求對象中讀取它們,將獲得以分號分隔的 key=value 對:

http.createServer(function (request, response) {
const cookies = request.headers.cookie;
// "cookie1=value1; cookie2=value2"
...
}).listen(8124);

如果想要設(shè)置 cookie,可以在響應(yīng)頭中添加 Set-Cookie 頭,其中 cookie 采用 key=value 的格式,屬性用分號分隔:

response.writeHead(200, {
'Set-Cookie': 'mycookie=test; domain=example.com; Secure'
});

通常我們不會直接編寫 Node.js,而是與 ExpressJS 這樣的 Node.js 框架一起使用。使用 Express 可以更輕松地訪問和修改 cookie。只需添加一個像 cookie-parser 這樣的中間件,就可以通過 req.cookies 以 JavaScript 對象的形式獲得所有的 cookie。還可以使用 Express 內(nèi)置的 res.cookie() 方法來設(shè)置 cookie:

const express = require('express')
const cookieParser = require('cookie-parser')

const app = express()
app.use(cookieParser())

app.get('/', function (req, res) {
console.log('Cookies: ', req.cookies)
// Cookies: { cookie1: 'value1', cookie2: 'value2' }

res.cookie('name', 'tobi', { domain: 'example.com', secure: true })
})

app.listen(8080)

(3)Cookie 屬性

下面來深入了解 cookie 的屬性。除了名稱和值之外,cookie 還具有控制很多方面的屬性,包括安全方面、生命周期以及它們在瀏覽器中的訪問位置和方式等。

① Domain

Domain 屬性告訴瀏覽器允許哪些主機(jī)訪問 cookie。如果未指定,則默認(rèn)為設(shè)置 cookie 的同一主機(jī)。因此,當(dāng)使用客戶端 JavaScript 訪問 cookie 時,只能訪問與 URL 域相同的 cookie。同樣,只有與 HTTP 請求的域共享相同域的 cookie 可以與請求頭一起發(fā)送到服務(wù)端。

注意,擁有此屬性并不意味著可以為任何域設(shè)置 cookie,因?yàn)檫@顯然會帶來巨大的安全風(fēng)險(xiǎn)。此屬性存在的唯一原因就是減少域的限制并使 cookie 在子域上可訪問。例如,如果當(dāng)前的域是 abc.xyz.com,并且在設(shè)置 cookie 時如果不指定 Domain 屬性,則默認(rèn)為 abc.xyz.com,并且 cookie 將僅限于該域。但是,可能希望相同的 cookie 也可用于其他子域,因此可以設(shè)置 Domain=xyz.com 以使其可用于其他子域,如 def.xyz.com 和主域 xyz.com。

圖片

② Path

此屬性指定訪問 cookie 必須存在的請求 URL 中的路徑。除了將 cookie 限制到域之外,還可以通過路徑來限制它。路徑屬性為 Path=/store 的 cookie 只能在路徑 /store 及其子路徑 /store/cart、/store/gadgets 等上訪問。

③ Expires/Max-size

該屬性用來設(shè)置 cookie 的過期時間。若設(shè)置其值為一個時間,那么當(dāng)?shù)竭_(dá)此時間后,cookie 就會失效。不設(shè)置的話默認(rèn)值是 Session,意思是cookie會和session一起失效。當(dāng)瀏覽器關(guān)閉(不是瀏覽器標(biāo)簽頁) 后,cookie 就會失效。

除此之外,它還可以通過將過期日期設(shè)置為過去來刪除 cookie。

④ Secure

具有 Secure 屬性的 cookie 僅可以通過安全的 HTTPS 協(xié)議發(fā)送到服務(wù)器,而不會通過 HTTP 協(xié)議。這有助于通過使 cookie 無法通過不安全的連接訪問來防止中間人攻擊。除非網(wǎng)站實(shí)用不安全的 HTTP 連接,否則應(yīng)該始終將此屬性與所有 cookie 一起使用。

⑤ HTTPOnly

此屬性使 cookie 只能通過服務(wù)端訪問。因此,只有服務(wù)斷可以通過響應(yīng)頭設(shè)置它們,然后瀏覽器會將它們與每個后續(xù)請求的頭一起發(fā)送到服務(wù)器,并且它們將無法通過客戶端 JavaScript 訪問。

圖片

這可以在一定程度上幫助保護(hù)帶有敏感信息(如身份驗(yàn)證 token)的 cookie 免受 XSS 攻擊,因?yàn)槿魏慰蛻舳四_本都無法讀取 cookie。但這并不意味著可以完全免受 XSS 攻擊。因?yàn)?,如果攻擊者可以在網(wǎng)站上執(zhí)行第三方腳本,那可能無法訪問 cookie,相反,他們可以直接向服務(wù)端執(zhí)行相關(guān)的 API 請求。因此,想象一下用戶訪問了一個頁面,黑客在網(wǎng)站上注入了惡意腳本。他們可以使用該腳本執(zhí)行任何 API,并在他們不知道的情況下代表用戶執(zhí)行操作。

(4)Cookie 工具庫

①  Js Cookie(JavaScript)

Js Cookie 是一個簡單、輕量級的 JavaScript API,用于處理瀏覽器 cookie。其支持 AMD、CommonJS 和 ES 模塊、沒有依賴關(guān)系、經(jīng)過徹底測試、支持自定義編碼和解碼、通用瀏覽器支持。

安裝:

npm i js-cookie

使用:

// 設(shè)置 Cookie
Cookies.set('cookie-name', 'cookie-value', { expires: 14})

// 讀取 Cookie
Cookies.get('cookie-name')

// 刪除 Cookie
Cookies.remove('cookie-name')

② React Cookie(React)

React Cookie 是一個專門用于 React 的 cookie 庫,它繼承了 Universal Cookie 庫的功能。它提供了一組組件和 Hooks,使 React 中的 cookie 處理非常簡單。如果使用的是 React 16.8+ 版本,就可以使用 hooks 來處理 cookie。否則,必須使用其提供的組件。

安裝:

npm i react-cookie

React Cookie 提供了 3 個 Hook,分別是 cookie、setCookie 和 removeCookie??梢允褂眠@些 Hook 來處理 React 應(yīng)用中的 cookie。

const [cookies, setCookie, removeCookie] = useCookies(['cookie-name']);
// 設(shè)置 Cookie
setCookie(name, value, [options]);
// 刪除 Cookie
removeCookie(name, [options])

③ Cookies(Node.js)

Cookies 是用于 HTTP cookie 配置的流行 NodeJS 模塊之一??梢暂p松地將其與內(nèi)置的 NodeJS HTTP 庫集成或?qū)⑵溆米?Express 中間件。它允許使用 Keygrip 對 cookie 進(jìn)行簽名以防止篡改、支持延遲 cookie 驗(yàn)證、不允許通過不安全的套接字發(fā)送安全 cookie、允許其他庫在不知道簽名機(jī)制的情況下訪問 cookie。

安裝:

npm install cookies

使用:

const cookie = require('cookie');
cookies = new Cookies( request, response, [ options ] )

// 讀取 cookies
cookies.get( name, [ options ] )

// 設(shè)置 cookies
cookies.set( name, [ value ], [ options ] )

4. IndexedDB

(1)概述

IndexedDB 提供了一個類似 NoSQL 的 key/value 數(shù)據(jù)庫,它可以存儲大量結(jié)構(gòu)化數(shù)據(jù),甚至是文件和 blob。每個域至少有 1GB 的可用空間,并且最多可以達(dá)到剩余磁盤空間的 60%。

IndexedDB 于 2011 年首次實(shí)現(xiàn),并于 2015 年 1 月成為 W3C 標(biāo)準(zhǔn),它具有良好的瀏覽器支持:

圖片

key/value 數(shù)據(jù)庫意味著存儲的所有數(shù)據(jù)都必須分配給一個 key。它將key 與 value 相關(guān)聯(lián),key 用作該值的唯一標(biāo)識符,這意味著可以使用該 key 跟蹤該值。如果應(yīng)用需要不斷獲取數(shù)據(jù),key/value 數(shù)據(jù)庫使用非常高效且緊湊的索引結(jié)構(gòu)來快速可靠地通過 key 定位值。使用該 key,不僅可以檢索存儲的值,還可以刪除、更新和替換該值。

圖片

在說 IndexedDB 之前,先來看一些相關(guān)術(shù)語:

  • 數(shù)據(jù)庫: 一個域可以創(chuàng)建任意數(shù)量的 IndexedDB 數(shù)據(jù)庫,只有同一域內(nèi)的頁面才能訪問數(shù)據(jù)庫。
  • object store:相關(guān)數(shù)據(jù)項(xiàng)的 key/value 存儲。它類似于 MongoDB 中的集合或關(guān)系數(shù)據(jù)庫中的表。
  • key:用于引用 object store 中每條記錄(值)的唯一名稱。它可以使用自動增量數(shù)字生成,也可以設(shè)置為記錄中的任何唯一值。
  • index:在 object store 中組織數(shù)據(jù)的另一種方式。搜索查詢只能檢查 key 或 index。
  • schema:object store、key 和 index 的定義。
  • version:分配給 schema 的版本號(整數(shù))。IndexedDB 提供自動版本控制,因此可以將數(shù)據(jù)庫更新到最新 schema。
  • 操作:數(shù)據(jù)庫活動,例如創(chuàng)建、讀取、更新或刪除記錄。

圖片

(2)特點(diǎn)及使用場景

indexedDB 特點(diǎn)如下:

  • 可以將任何 JavaScript 類型的數(shù)據(jù)存儲為鍵值對,例如對象(blob、文件)或數(shù)組等。
  • IndexedDB API 是異步的,不會在數(shù)據(jù)加載時停止頁面的渲染。
  • 可以存儲結(jié)構(gòu)化數(shù)據(jù),例如 Date、視頻、圖像對象等。
  • 支持?jǐn)?shù)據(jù)庫事務(wù)和版本控制。
  • 可以存儲大量數(shù)據(jù)。
  • 可以在大量數(shù)據(jù)中快速定位/搜索數(shù)據(jù)。
  • 數(shù)據(jù)庫是域?qū)S玫模虼巳魏纹渌军c(diǎn)都無法訪問其他網(wǎng)站的 IndexedDB 存儲,這也稱為同源策略。

IndexedDB 使用場景:

存儲用戶生成的內(nèi)容: 例如表單,在填寫表單的過程中,用戶可以離開并稍后再回來完成表單,存儲之后就不會丟失初始輸入的數(shù)據(jù)。

存儲應(yīng)用狀態(tài): 當(dāng)用戶首次加載網(wǎng)站或應(yīng)用時,可以使用 IndexedDB 存儲這些初始狀態(tài)??梢允堑卿浬矸蒡?yàn)證、API 請求或呈現(xiàn) UI 之前所需的任何其他狀態(tài)。因此,當(dāng)用戶下次訪問該站點(diǎn)時,加載速度會增加,因?yàn)閼?yīng)用已經(jīng)存儲了狀態(tài),這意味著它可以更快地呈現(xiàn) UI。

對于離線工作的應(yīng)用: 用戶可以在應(yīng)用離線時編輯和添加數(shù)據(jù)。當(dāng)應(yīng)用程序來連接時,IndexedDB 將處理并清空同步隊(duì)列中的這些操作。

(3)IndexedDB 操作

不同瀏覽器的 IndexedDB 可能使用不同的名稱??梢允褂靡韵路椒z查 IndexedDB 支持:

const indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB ||
window.shimIndexedDB;

if (!indexedDB) {
console.log("不支持 IndexedDB");
}

可以使用 indexedDB.open() 來連接數(shù)據(jù)庫:

const dbOpen = indexedDB.open('performance', 1);

indexedDB.open 的第一個參數(shù)是數(shù)據(jù)庫名稱,第二個參數(shù)是可選的版本整數(shù)。

可以使用以下三個事件處理函數(shù)監(jiān)聽 indexedDB 的連接狀態(tài):

① onerror

在無法建立 IndexedDB 連接時,將觸發(fā)該事件:

// 連接失敗
dbOpen.onerror = e {
reject(`IndexedDB error: ${ e.target.errorCode }`);
};

如果在無痕模式、隱私模式下運(yùn)行瀏覽器,可能不支持 IndexedDB,需要禁用這些模式。

② onupgradeneeded

一旦數(shù)據(jù)庫連接打開,就會觸發(fā) onupgradeneeded 事件,該事件可用于創(chuàng)建 object store。

dbOpen.onupgradeneeded = e {
const db = dbOpen.result;

// 創(chuàng)建 object store
const store = db.createObjectStore("cars", { keyPath: "id" });
// 使用自動遞增的id
// const store = db.createObjectStore('cars', { autoIncrement: true });

// 創(chuàng)建索引

store.createIndex("cars_colour", ["colour"], {
unique: true
});

// 創(chuàng)建復(fù)合索引
store.createIndex("colour_and_make", ["colour", "make"], {
unique: false,
});
};

IndexedDB 使用了 object store 的概念,其本質(zhì)上是數(shù)據(jù)集合的名稱??梢栽趩蝹€數(shù)據(jù)庫中創(chuàng)建任意數(shù)量的 object store。keyPath是 IndexedDB 將用來識別對象字段名稱,通常是一個唯一的編號,也可以通過 autoIncrement: true 來自動為 store 設(shè)置唯一遞增的 ID。除了普通的索引,還可以創(chuàng)建復(fù)合索引,使用多個關(guān)鍵詞的組合進(jìn)行查詢。

③ onsuccess

在連接建立并且所有升級都完成時,將觸發(fā)該事件。上面我們已經(jīng)新建了 schema,接下來就可以在onsuccess 中添加、查詢數(shù)據(jù)。

// 連接成功
dbOpen.onsuccess = () {
this.db = dbOpen.result;

//1
const transaction = db.transaction("cars", "readwrite");

//2
const store = transaction.objectStore("cars");
const colourIndex = store.index("cars_colour");
const makeModelIndex = store.index("colour_and_make");

//3
store.put({ id: 1, colour: "Red", make: "Toyota" });
store.put({ id: 2, colour: "Red", make: "Kia" });
store.put({ id: 3, colour: "Blue", make: "Honda" });
store.put({ id: 4, colour: "Silver", make: "Subaru" });

//4
const idQuery = store.get(4);
const colourQuery = colourIndex.getAll(["Red"]);
const colourMakeQuery = makeModelIndex.get(["Blue", "Honda"]);

// 5
idQuery.onsuccess = function () {
console.log('idQuery', idQuery.result);
};
colourQuery.onsuccess = function () {
console.log('colourQuery', colourQuery.result);
};
colourMakeQuery.onsuccess = function () {
console.log('colourMakeQuery', colourMakeQuery.result);
};

// 6
transaction.oncomplete = function () {
db.close();
};
};

這里總共有六部分:

為了對數(shù)據(jù)庫執(zhí)行操作,我們必須創(chuàng)建一個 schema,一個 schema 可以是單個操作,也可以是多個必須全部成功的操作,否則都不會成功;

這里用來獲取 cars object store 的引用以及對應(yīng)的索引;

object store 上的 put 方法用于將數(shù)據(jù)添加到數(shù)據(jù)庫中;

這里就是數(shù)據(jù)的查詢,可以使用 keyPath 的值直接查詢項(xiàng)目(第14行);第15行中的 getAll 方法將返回一個包含它找到的每個結(jié)果的數(shù)組,我們正在根據(jù)  cars_colour 索引來搜索 Red,應(yīng)該會查找到兩個結(jié)果。第16行根據(jù)復(fù)合索引查找顏色為Blue,并且品牌為 Honda 的結(jié)果。

搜索成功的事件處理函數(shù),它們將在查詢完成時觸發(fā)。

最后,在事務(wù)完成時關(guān)閉與數(shù)據(jù)庫連接。無需使用 IndexedDB 手動觸發(fā)事務(wù),它會自行運(yùn)行。

運(yùn)行上面的代碼,就會得到以下結(jié)果:

圖片

可以在 Chrome Devtools 中查看:

圖片

下面來看看如何更新和刪除數(shù)據(jù)。

更新: 首先使用個 get 來獲取需要更新的數(shù)據(jù),然后使用 store 上的 put 方法更新現(xiàn)有數(shù)據(jù)。put 是一種“插入或更新”方法,它要么覆蓋現(xiàn)有數(shù)據(jù),要么在新數(shù)據(jù)不存在時插入新數(shù)據(jù)。

const subaru = store.get(4);

subaru.notallow= function () {
subaru.result.colour = "Green";
store.put(subaru.result);
}

這會將數(shù)據(jù)庫中 Silver 色的 Subaru 的顏色更新為綠色。

刪除:可以使用 delete API 來刪除數(shù)據(jù),最簡單的方法是通過其 key 來刪除:

const deleteCar = store.delete(1);

deleteCar.onsuccess = function () {
console.log("Removed");
};

如果不知道 key 并且希望根據(jù)值來刪除,可以這樣:

const redCarKey = colourIndex.getKey(["Red"]);

redCarKey.onsuccess = function () {
const deleteCar = store.delete(redCarKey.result);

deleteCar.onsuccess = function () {
console.log("Removed");
};
};

結(jié)果如下:

圖片

5. 存儲空間分析

可以使用基于 Promise 的 Storage API 檢查 Web Storage、IndexedDB 和 Cache API 的剩余空間。異步 .estimate() 方法返回:

  • quota 屬性:可用的空間;
  • usage 屬性:已用的空間。
(async () => {
if (!navigator.storage) return;

const storage = await navigator.storage.estimate();

console.log(`可用大小: ${ storage.quota / 1024 } Kb`);
console.log(`已用大小: ${ storage.usage / 1024 } Kb`);
console.log(`已用占比: ${ Math.round((storage.usage / storage.quota) * 100) }%`);
console.log(`剩余大小: ${ Math.floor((storage.quota - storage.usage) / 1024) } Kb`);
})();

Storage API 的瀏覽器兼容性如下:

圖片

責(zé)任編輯:武曉燕 來源: 前端充電寶
相關(guān)推薦

2018-04-27 09:22:21

數(shù)據(jù)存儲技巧

2018-07-03 08:48:48

對象存儲塊存儲

2020-05-09 14:20:11

信息安全加密

2018-06-25 09:32:44

2018-05-16 08:58:04

用戶畫像存儲

2020-07-14 08:53:43

Redis數(shù)據(jù)存儲

2020-11-17 06:57:15

存儲互聯(lián)網(wǎng)用戶

2021-07-30 10:33:57

MySQL觸發(fā)器數(shù)據(jù)

2020-07-16 14:40:23

大數(shù)據(jù)計(jì)算框架

2017-12-27 08:34:36

軟件存儲SDS

2023-07-06 13:56:14

微軟Skype

2019-12-12 14:52:10

數(shù)據(jù)庫腳本

2017-12-26 10:19:14

大數(shù)據(jù)問題缺陷

2020-09-08 06:54:29

Java Gradle語言

2020-03-06 15:11:21

進(jìn)程線程Web

2018-04-25 09:01:02

2022-08-30 10:15:27

Kubernetes數(shù)據(jù)持久化管理

2023-09-22 17:36:37

2021-01-28 22:31:33

分組密碼算法

2020-05-22 08:16:07

PONGPONXG-PON
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號