您好,登錄后才能下訂單哦!
小編給大家分享一下瀏覽器中的不同存儲類型有哪些,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!
在后端開發中,存儲是工作的常見部分。應用程序數據存儲在數據庫中,文件存儲在對象存儲中,瞬態數據存儲在高速緩存中……似乎存在無限種存儲任何類型數據的可能性。但是,數據存儲不僅限于后端,前端(瀏覽器)還具有許多存儲數據的選項。我們可以通過利用這種存儲方式來提升我們的應用性能,保存用戶的偏好,在多個會話,甚至不同的計算機上保持應用狀態。
在本文中,我們將通過不同的可能性在瀏覽器中存儲數據。我們將涵蓋每種方法的三個用例,以掌握其利弊。最后,你將能夠決定什么存儲是最適合你的用例。
讓我們開始吧!
localStorage
是瀏覽器中最受歡迎的存儲選項之一,也是許多開發人員的首選。數據跨會話存儲,從不與服務器共享,并且可用于同一協議和域下的所有頁面。存儲空間限制為?5MB。
令人驚訝的是,谷歌Chrome團隊并不建議使用這個選項,因為它屏蔽了主線程,而且web workers和service workers無法訪問。他們推出了一個實驗:KV Storage,作為一個更好的版本,但這只是一個試驗,似乎還沒有任何進展。
localStorage API
可作為 window.localStorage
使用,并且只能保存UTF-16字符串。在將數據保存到 localStorage
之前,我們必須確保將其轉換為字符串。主要的三個功能是:
setItem('key',
'value')
getItem('key')
removeItem('key')
它們都是同步的,因此使用起來很簡單,但是它們會阻塞主線程。
值得一提的是,localStorage
有一個稱為 sessionStorage
的雙胞胎。唯一的區別是,存儲在 sessionStorage
中的數據將僅持續當前會話,但API相同。
這個太簡單了,相信大家都用過。
IndexedDB是瀏覽器中的現代存儲解決方案。它可以存儲大量的結構化數據,甚至文件和Blob。和每一個數據庫一樣,IndexedDB對數據進行索引,以便高效地運行查詢。使用IndexedDB比較復雜,我們必須創建一個數據庫,表,并使用事務。
與 localStorage
相比,IndexedDB需要更多代碼。在例子中,我使用了原生API與Promise包裝器,但我強烈建議使用第三方庫來幫助你。我推薦的是localForage,因為它使用了同樣的 localStorage
API,但實現方式是逐步增強的,也就是說,如果你的瀏覽器支持IndexedDB,就會使用它;如果不支持,就會退回到 localStorage
。
讓我們來編寫代碼,前往我們的用戶偏好示例吧!
<input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'> <label for="darkTheme">Dark theme</label><br>
let db; function toggle(on) { if (on) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } async function save(on) { const tx = db.transaction('preferences', 'readwrite'); const store = tx.objectStore('preferences'); store.put({key: 'darkTheme', value: on}); return tx.complete; } async function load() { const tx = db.transaction('preferences', 'readonly'); const store = tx.objectStore('preferences'); const data = await store.get('darkTheme'); return data && data.value; } async function onChange(checkbox) { const value = checkbox.checked; toggle(value); await save(value); } function openDatabase() { return idb.openDB('my-db', 1, { upgrade(db) { db.createObjectStore('preferences', {keyPath: 'key'}); }, }); } openDatabase() .then((_db) => { db = _db; return load(); }) .then((initialValue) => { toggle(initialValue); document.querySelector('#darkTheme').checked = initialValue; });
效果
idb
是我們使用的Promise包裝器,而不是使用基于事件的低級API。首先要注意的是,對數據庫的每次訪問都是異步的,這意味著我們不會阻塞主線程,與 localStorage
相比,這是一個主要優勢。
我們需要打開與數據庫的連接,以便在整個應用程序中都可以使用它進行讀寫。我們給數據庫起一個名字 my-db
,一個模式版本 1
,以及一個更新函數,以在版本之間應用更改,這與數據庫遷移非常相似。我們的數據庫架構很簡單:只有一個object store preferences
。object store 等效于SQL表,要寫入或讀取數據庫,必須使用事務,這是使用IndexedDB的乏味部分。看一下演示中新的 save
和 load
功能。
毫無疑問,IndexedDB具有更多的開銷,并且與 localStorage
相比,學習曲線更陡峭。對于鍵值的情況,使用 localStorage
或第三方庫可能更有意義,它們將幫助我們提高效率。
<p id="loading">loading...</p> <ul id="list"> </ul>
let db; async function loadPokemons() { const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10'); const data = await res.json(); return data.results; } function removeLoading() { const elem = document.querySelector('#loading'); if (elem) { elem.parentNode.removeChild(elem); } } function appendPokemon(pokemon) { const node = document.createElement('li'); const textnode = document.createTextNode(pokemon.name); node.appendChild(textnode); document.querySelector('#list').appendChild(node); } function clearList() { const list = document.querySelector('#list'); while (list.firstChild) { list.removeChild(list.lastChild); } } function saveToCache(pokemons) { const tx = db.transaction('pokemons', 'readwrite'); const store = tx.objectStore('pokemons'); pokemons.forEach(pokemon => store.put(pokemon)); return tx.complete; } function loadFromCache() { const tx = db.transaction('pokemons', 'readonly'); const store = tx.objectStore('pokemons'); return store.getAll(); } function openDatabase() { return idb.openDB('my-db2', 1, { upgrade(db) { db.createObjectStore('pokemons', {keyPath: 'name'}); }, }); } openDatabase() .then((_db) => { db = _db; return loadFromCache(); }) .then((cachedPokemons) => { if (cachedPokemons) { removeLoading(); cachedPokemons.forEach(appendPokemon); console.log('loaded from cache!'); } return loadPokemons(); }) .then((pokemons) => { removeLoading(); saveToCache(pokemons); clearList(); pokemons.forEach(appendPokemon); console.log('loaded from network!'); });
效果
你可以在此數據庫中存儲數百兆甚至更多。您可以將所有Pokémon存儲在IndexedDB中,并使其脫機甚至建立索引!這絕對是用于存儲應用程序數據的一種選擇。
我跳過了第三個示例的實現,因為與 localStorage
相比,IndexedDB在這種情況下沒有任何區別。即使使用 IndexedDB,用戶仍然不會與他人分享所選頁面,也不會將其作為書簽供將來使用。它們都不適合這個用例。
使用cookies是一種獨特的存儲方式,這是唯一的與服務器共享的存儲方式。Cookies作為每次請求的一部分被發送。它可以是當用戶瀏覽我們的應用程序中的頁面或當用戶發送Ajax請求時。這樣我們就可以在客戶端和服務器之間建立一個共享狀態,也可以在不同子域的多個應用程序之間共享狀態。本文中介紹的其他存儲選項無法實現。需要注意的是:每個請求都會發送 cookie
,這意味著我們必須保持 cookie 較小,以保持適當的請求大小。
Cookies的最常見用途是身份驗證,這不在本文的討論范圍之內。就像 localStorage
一樣,cookie
只能存儲字符串。這些cookie被連接成一個以分號分隔的字符串,并在請求的cookie頭中發送。你可以為每個cookie設置很多屬性,比如過期、允許的域名、允許的頁面等等。
在例子中,我展示了如何通過客戶端來操作cookie,但也可以在你的服務器端應用程序中改變它們。
<input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'> <label for="darkTheme">Dark theme</label>
function getCookie(cname) { const name = cname + '='; const decoded = decodeURIComponent(document.cookie); const split = decoded.split(';'); const relevantCookie = split.find((cookie) => cookie.indexOf(`${cname}=`) === 0); if (relevantCookie) { return relevantCookie.split('=')[1]; } return null; } function toggle(on) { if (on) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } function save(on) { document.cookie = `dark_theme=${on.toString()}; max-age=31536000; SameSite=None; Secure`; } function load() { return getCookie('dark_theme') === 'true'; } function onChange(checkbox) { const value = checkbox.checked; toggle(value); save(value); } const initialValue = load(); toggle(initialValue); document.querySelector('#darkTheme').checked = initialValue;
效果還是跟前面一樣
將用戶的喜好保存在cookie中,如果服務器能夠以某種方式利用它,就可以很好地滿足用戶的需求。例如,在主題用例中,服務器可以交付相關的CSS文件,并減少潛在的捆綁大小(在我們進行服務器端渲染的情況下)。另一個用例可能是在沒有數據庫的情況下,在多個子域應用之間共享這些偏好。
用JavaScript讀寫cookie并不像您想象的那么簡單。要保存新的cookie,您需要設置 document.cookie
——在上面的示例中查看 save
函數。我設置了 dark_theme
cookie,并給它添加了一個 max-age
屬性,以確保它在關閉標簽時不會過期。另外,我添加 SameSite
和 Secure
屬性。這些都是必要的,因為CodePen使用iframe來運行這些例子,但在大多數情況下你并不需要它們。讀取一個cookie需要解析cookie字符串。
Cookie字符串如下所示:
key1=value1;key2=value2;key3=value3
因此,首先,我們必須用分號分隔字符串。現在,我們有一個形式為 key1=value1
的Cookie數組,所以我們需要在數組中找到正確的元素。最后,我們將等號分開并獲得新數組中的最后一個元素。有點繁瑣,但一旦你實現了 getCookie
函數(或從我的例子中復制它:P),你就可以忘記它。
將應用程序數據保存在cookie中可能是個壞主意!它將大大增加請求的大小,并降低應用程序性能。此外,服務器無法從這些信息中獲益,因為它是數據庫中已有信息的陳舊版本。如果你使用cookies,請確保它們很小。
分頁示例也不適合cookie,就像 localStorage
和 IndexedDB
一樣。當前頁面是我們想要與他人共享的臨時狀態,這些方法都無法實現它。
URL本身并不是存儲設備,但它是創建可共享狀態的好方法。實際上,這意味著將查詢參數添加到當前URL中,這些參數可用于重新創建當前狀態。最好的例子是搜索查詢和過濾器。如果我們在CSS-Tricks上搜索術語flexbox,則URL將更新為https://css-tricks.com/?s=fle...。看看我們使用URL后,分享搜索查詢有多簡單?另一個好處是,你只需點擊刷新按鈕,就可以獲得更新的查詢結果,甚至可以將其收藏。
我們只能在URL中保存字符串,它的最大長度是有限的,所以我們沒有那么多的空間。我們將不得不保持我們的狀態小,沒有人喜歡又長又嚇人的網址。
同樣,CodePen使用iframe運行示例,因此您看不到URL實際更改。不用擔心,因為所有的碎片都在那里,所以你可以在任何你想要的地方使用它。
<input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'> <label for="darkTheme">Dark theme</label>
function toggle(on) { if (on) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } function save(on) { const params = new URLSearchParams(window.location.search); params.set('dark_theme', on.toString()); history.pushState(null, null, `?${params.toString()}`); } function load() { const params = new URLSearchParams(window.location.search); return params.get('dark_theme') === 'true'; } function onChange(checkbox) { const value = checkbox.checked; toggle(value); save(value); } const initialValue = load(); toggle(initialValue); document.querySelector('#darkTheme').checked = initialValue;
效果還是一樣
我們可以通過 window.location.search
訪問查詢字符串,幸運的是,可以使用 URLSearchParams
類對其進行解析,無需再應用任何復雜的字符串解析。當我們想讀取當前值時,可以使用 get
函數,當我們想寫時,可以使用 set
。僅設置值是不夠的,我們還需要更新URL。這可以使用 history.pushState
或 history.replaceState
來完成,取決于我們想要完成的行為。
我不建議將用戶的偏好保存在URL中,因為我們必須將這個狀態添加到用戶訪問的每一個URL中,而且我們無法保證;例如,如果用戶點擊了谷歌搜索的鏈接。
就像Cookie一樣,由于空間太小,我們無法在URL中保存應用程序數據。而且即使我們真的設法存儲它,網址也會很長,而且不吸引人點擊。可能看起來像是釣魚攻擊的一種。
<p>Select page:</p> <p id="pages"> <button onclick="updatePage(0)">0</button> <button onclick="updatePage(1)">1</button> <button onclick="updatePage(3)">3</button> <button onclick="updatePage(4)">4</button> <button onclick="updatePage(5)">5</button> </p> <ul id="list"> </ul>
async function loadPokemons(page) { const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=10&offset=${page * 10}`); const data = await res.json(); return data.results; } function appendPokemon(pokemon) { const node = document.createElement('li'); const textnode = document.createTextNode(pokemon.name); node.appendChild(textnode); document.querySelector('#list').appendChild(node); } function clearList() { const list = document.querySelector('#list'); while (list.firstChild) { list.removeChild(list.lastChild); } } function savePage(page) { const params = new URLSearchParams(window.location.search); params.set('page', page.toString()); history.pushState(null, null, `?${params.toString()}`); } function loadPage() { const params = new URLSearchParams(window.location.search); if (params.has('page')) { return parseInt(params.get('page')); } return 0; } async function updatePage(page) { clearList(); savePage(page); const pokemons = await loadPokemons(page); pokemons.forEach(appendPokemon); } const page = loadPage(); updatePage(page);
效果
就像我們的分頁例子一樣,臨時應用狀態是最適合URL查詢字符串的。同樣,你無法看到URL的變化,但每次點擊一個頁面時,URL都會以 ?page=x
查詢參數更新。當網頁加載時,它會查找這個查詢參數,并相應地獲取正確的頁面。現在,我們可以把這個網址分享給我們的朋友,讓他們可以享受我們最喜歡的神奇寶貝。
Cache API是網絡級的存儲,它用于緩存網絡請求及其響應。Cache API非常適合service worker,service worker可以攔截每一個網絡請求,使用 Cache API 它可以輕松地緩存這兩個請求。service worker也可以將現有的緩存項作為網絡響應返回,而不是從服務器上獲取。這樣,您可以減少網絡負載時間,并使你的應用程序即使處于脫機狀態也能正常工作。最初,它是為service worker創建的,但在現代瀏覽器中,Cache API也可以在窗口、iframe和worker上下文中使用。這是一個非常強大的API,可以極大地改善應用的用戶體驗。
就像IndexedDB一樣,Cache API的存儲不受限制,您可以存儲數百兆字節,如果需要甚至可以存儲更多。API是異步的,所以它不會阻塞你的主線程,而且它可以通過全局屬性 caches
來訪問。
如果你建立一個瀏覽器擴展,你有另一個選擇來存儲你的數據,我在進行擴展程序daily.dev時發現了它。如果你使用Mozilla的polyfill,它可以通過 chrome.storage
或 browser.storage
獲得。確保在你的清單中申請一個存儲權限以獲得訪問權。
有兩種類型的存儲選項:local和sync。local存儲是不言而喻的,它的意思是不共享,保存在本地。sync存儲是作為谷歌賬戶的一部分同步的,你在任何地方用同一個賬戶安裝擴展,這個存儲都會被同步。兩者都有相同的API,所以如果需要的話,來回切換超級容易。它是異步存儲,因此不會像 localStorage
這樣阻塞主線程。不幸的是,我不能為這個存儲選項創建一個演示,因為它需要一個瀏覽器擴展,但它的使用非常簡單,幾乎和 localStorage
一樣。有關確切實現的更多信息,請參閱Chrome文檔。
瀏覽器有許多選項可用于存儲數據。根據Chrome團隊的建議,我們的首選存儲應該是IndexedDB,它是異步存儲,有足夠的空間來存儲我們想要的任何東西。不鼓勵使用 localStorage
,但它比 IndexedDB
更易于使用。Cookies是與服務器共享客戶端狀態的一種好方法,但通常用于身份驗證。
如果你想創建具有可共享狀態的頁面,如搜索頁面,請使用URL的查詢字符串來存儲這些信息。最后,如果你建立一個擴展,一定要閱讀關于 chrome.storage
。
看完了這篇文章,相信你對瀏覽器中的不同存儲類型有哪些有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。