HTML5 離線存儲
本章介紹一下 HTML5 新增的離線存儲特性 Localstorage,主要包括 Localstorage 的發(fā)展史、兼容性、優(yōu)缺點以及使用場景。
說到 Localstorage,為什么要使用 Localstorage 呢?
因為開發(fā)程序當(dāng)然就要存儲數(shù)據(jù)了,但是 Web 開發(fā)場景比較特殊,數(shù)據(jù)正常情況下是要通過 HTTP 協(xié)議發(fā)送給服務(wù)器端,存儲在服務(wù)器上,但是呢,如果所有數(shù)據(jù)都存到服務(wù)器一方面會浪費服務(wù)器資源,另一方面也會降低網(wǎng)頁響應(yīng)速度,所以設(shè)計網(wǎng)頁時會抽取一些不太重要的或者臨時性的數(shù)據(jù)使用離線存儲方式放在瀏覽器上。
總的來說,Localstorage 是一個簡單的離線存儲技術(shù),通過官方提供的增刪改查的 API 可以方便的操作它,需要考慮的難點是每個瀏覽器的容量限制,使用時做好容錯即可。
1. 離線存儲發(fā)展史
在早期的互聯(lián)網(wǎng)發(fā)展中,瀏覽器制定了不同的標(biāo)準(zhǔn)用于存儲離線數(shù)據(jù),其中比較出名的有微軟 IE 瀏覽器的 userData(單個頁面可存儲 64 kb)、Adobe 的 flash6 中的 flash-cookies(允許存儲 100kb)、flash8 中的 externalinterface、Google 的 gears,不幸的是這些技術(shù)沒有統(tǒng)一的標(biāo)準(zhǔn),而且只適用于單一的瀏覽器,不能跨平臺,所以沒有收錄在 HTML 標(biāo)準(zhǔn)中。HTML5 之前,Cookie 是唯一在 HTML 標(biāo)準(zhǔn)中用于離線存儲的技術(shù),但是 Cookie 有一些不太友好的特征限制了它的應(yīng)用場景:
- Cookie 會被附加在 HTTP 協(xié)議中,每次請求都會被發(fā)送到服務(wù)器端,增加了不必要的流量損耗
- Cookie 大小限制在 4kb 左右(不同的瀏覽器有一些區(qū)別),對于一些復(fù)雜的業(yè)務(wù)場景可能不夠
這兩個缺點在 Localstorage 中得到了有效的解決,下面我們就開始學(xué)習(xí) Localstorage。
2. 兼容性
截止目前為止,已經(jīng)有大部分瀏覽器已經(jīng)支持 Localstorage,包括 IE8。
具體瀏覽器是否支持 Localstorage 可以通過簡單的 JavaScript 代碼判斷。
function testLocalstorage(){
if ( typeof window.localStorage == "object" ) return true;//判斷l(xiāng)ocalstorage對象是否定義
else return false;//未定義返回false
}
3. API 接口
Localstorage 是一個簡單的 key/value 形式的數(shù)據(jù)庫,以鍵值對的方式存儲,所以提供的接口主要是基于 k/v 的操作。基于提供的接口只能存儲簡單的一維數(shù)組,但是有些業(yè)務(wù)場景可能會牽涉到多維數(shù)據(jù)甚至對象的存儲,怎么辦?
- 建議使用
JSON.stringify()
將數(shù)據(jù)轉(zhuǎn)化成字符串方式再存儲; - 使用復(fù)雜的前端數(shù)據(jù)庫,例如 indexDB,具體不做深入討論。
3.1 存儲數(shù)據(jù)
window.localStorage.setItem("test",1)//設(shè)置key=test的值為1
localStorage.setItem("test",1)//設(shè)置key=test的值為1,localstorage可以作為全局對象處理
localStorage.test = 1//可以通過屬性值的方式直接操作localstorage的key
運行下面案例代碼,試一試:
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
window.localStorage.setItem("test",1)//設(shè)置key=test的值為1
localStorage.setItem("test",1)//設(shè)置key=test的值為1,localstorage可以作為全局對象處理
localStorage.test = 1//可以通過屬性值的方式直接操作localstorage的key
document.getElementById("demo").innerHTML =
"localStorage.test 的值是" + localStorage.test + "。";
</script>
</body>
</html>
3.2 讀取數(shù)據(jù)-按鍵值
getItem
var a = window.localStorage.getItem("test")//獲取key=test的值
var a = localStorage.test//可以直接通過對象屬性的方式操作
如果獲取一個不存在的 key 返回 null ,下同。
3.3 讀取數(shù)據(jù)-按位置
var a = window.localStorage.key(0)//可以根據(jù)key在localstorage的位置的方式操作,類似操作JavaScript的array的方式
3.4 刪除數(shù)據(jù)
window.localStorage.removeItem("test")//刪除key=test的值
window.localStorage.test = ''//可以通過賦空值的方式等價操作
3.5 整體清空
window.localStorage.clear()//clear函數(shù)清空整個localstorage
3.6 存儲事件監(jiān)聽
當(dāng) localstorage 發(fā)生改變時,可以通過監(jiān)聽 storage 事件作出相應(yīng)的業(yè)務(wù)處理。
if (window.addEventListener) { //通過addEventListener方式監(jiān)聽事件,為了兼容IE
window.addEventListener("storage", function(e){//監(jiān)聽storage事件
//業(yè)務(wù)處理
}, false);
} else {
window.attachEvent("onstorage", function(e){//通過attachEvent方式監(jiān)聽事件
//業(yè)務(wù)處理
});
}
4. 適用場景及局限性
4.1 局限性
前邊提到 Localstorage 相比較 Cookie 的優(yōu)勢是容量大和節(jié)省 HTTP 帶寬,但是它還是有自身的缺點,下邊羅列了它的缺點
- 5M 容量依然小,用過數(shù)據(jù)庫的同學(xué)應(yīng)該知道,MySQL 隨便一個表加上索引很容易超過 5M
- 不能跨域名訪問,同一個網(wǎng)站可能會牽涉到子域名
- 不能存儲關(guān)系型數(shù)據(jù)
- 不能搜索
4.2 適用場景
那么以上缺點有沒有解決方案,肯定是有的,例如 HTML 的 webSql 或者 indexDB,那肯定有人問了,為什么不直接用最復(fù)雜的數(shù)據(jù)庫,跳過 Localstorage 呢?原因是技術(shù)沒有最好的,只有最適合的,不同的業(yè)務(wù)場景應(yīng)該選擇最匹配的而且成本最小的解決方案。例如你在存儲簡單的業(yè)務(wù)場景中的臨時數(shù)據(jù)時完全可以使用 Localstorage 甚至 Cookie 搞定,假如使用 indexDB 的話系統(tǒng)的開發(fā)成本以及維護成本會翻番,得不償失。
所以說總結(jié)下來 Localstorage 的適用業(yè)務(wù)場景是:
- 數(shù)據(jù)關(guān)系簡單明了
- 數(shù)據(jù)量小
- 數(shù)據(jù)無需持久化存儲且不需要考慮安全性
- 無需跟服務(wù)器交互
5. 業(yè)務(wù)實戰(zhàn)
5.1 項目使用場景
之前開發(fā)一個場館管理系統(tǒng)時有一個功能是根據(jù)用戶輸入的關(guān)鍵字搜索場館,業(yè)務(wù)方的需求是需要臨時保留搜索關(guān)鍵詞的歷史記錄,考慮到是臨時保存,而且只保存關(guān)鍵字不需要復(fù)雜的數(shù)據(jù)結(jié)構(gòu)存儲且只保存 10 條最新的數(shù)據(jù),項目組商量下來決定使用 Localstorage 保存,搜索成功之后添加到歷史記錄。
function chooseClubItem(e) {
let mid = e.currentTarget.dataset.id
let findAddressInfo = this.data.markers.find(item => item.id === mid)
const historyList = window.localStorage.getItem('historyList') || []//獲取localstorage需要操作的鍵值
if (findAddressInfo) {
const index = historyList.findIndex(history => history.id == findAddressInfo.id)
if (index !== -1) {
historyList.splice(index, 1)
}
if(historyList.length>=10)historyList.pop();//超過最大歷史數(shù)目,刪除最后一個
historyList.unshift(findAddressInfo)//加入到歷史存儲隊列中
window.localStorage.setItem('historyList', historyList)//設(shè)置離線存儲
}
},
清空歷史記錄
function delHistory() {
let that = this
showModal({//彈出確認(rèn)對話框
title: '',
content: '您確定要清空搜索歷史嗎',
showCancel: true,
cancelText: '取消',
cancelColor: '#000000',
confirmText: '確定',
confirmColor: '#3CC51F',
success: result => {
if (result.confirm) {
window.localStorage.removeItem("historyList")//情況歷史隊列
}
}
})
},
5.2 使用第三方庫
現(xiàn)實中考慮到瀏覽器對 Localstorage 畢竟不是百分之百兼容,而且 Localstorage 本身提供的 API 比較簡單,所以實際項目中可以考慮使用第三方封裝庫操作,比如 store.js。
store.js 優(yōu)先選擇 localStorage 來進行存儲,在 IE6 和 IE7 下降級使用 userData 來達到目的。 沒有使用 flash ,不會減慢你的頁面加載速度。也沒有使用 Cookies ,不會使你的網(wǎng)絡(luò)請求變得臃腫。store.js 依賴 JSON 來序列化數(shù)據(jù)進行存儲。
6. 總結(jié)
以上介紹了 Localstorage 和傳統(tǒng)離線存儲的優(yōu)缺點對比,Localstorage 的使用方法以及項目實戰(zhàn)分析。總的來說 Localstorage 適用于業(yè)務(wù)簡單的輕量級存儲中,通過簡單的 API 操作增刪改查存儲鍵值對,而且可以通過事件監(jiān)聽的方式獲取 Localstorage 的操作事件,無需發(fā)送 HTTP 請求,真正實現(xiàn)了離線存儲