其實這是很簡單的一個API。但這個API也存在不少問題可以深究一下。
說到這個API,我就想起曾經(jīng)一次面試:當時面試我的CTO拿出自己的iPhone6,打開一個網(wǎng)址,說這個頁面在其他所有的手機都沒問題,偏偏就是我的手機無法訪問。我一瞧,果然一片空白,然后我敏銳地發(fā)現(xiàn)他的瀏覽器開啟了隱私模式,我馬上就猜到這是隱私模式下設(shè)置Storage的問題。和CTO扯了一些關(guān)于Storage API的知識后,關(guān)掉隱私模式果然沒問題。
MDN
要探究Web API,首先就想到MDN。因為平常習(xí)慣了中文閱讀,所以也自然而然地打開中文語言。然而我腦袋一轉(zhuǎn),覺得這么簡單的API閱讀英文應(yīng)該也是比較簡單的吧,而且還可以順便對比一下中英文版本練練自己的翻譯。然而這個偶然的動作讓我發(fā)現(xiàn)了英語閱讀是多么地重要!
中英文版本的差異
中文版本漏翻譯了許多部分(有些還是很重要的),我覺得這估計是選擇性翻譯導(dǎo)致的問題。
比如:
- 我們可以像訪問對象一樣來訪問Storage
localStorage.colorSetting = '#a4509b';
localStorage['colorSetting'] = '#a4509b';
localStorage.setItem('colorSetting', '#a4509b');
但是,不推薦這樣使用,因為會有可能讀取到Storage原型鏈上的屬性,還有一些可能會遇到的“陷阱”,有一篇相關(guān)的閱讀可以看一下《The pitfalls of using objects as maps in JavaScript》。譯者忽略這段內(nèi)容,估計是覺得既然不推薦這樣使用,就干脆不告訴你了。雖然這部分內(nèi)容對使用這個API沒什么幫助,但是它關(guān)聯(lián)到了一些重要的其他JavaScript知識。
- 可用性檢測。這個是很重要的一點,和我前面提到的那個故事有著密切的聯(lián)系。因為在使用storage API的時候,我們需要檢測一下當前環(huán)境這個API是否可用,如果不可用還繼續(xù)使用的話,用戶代理(一般就指瀏覽器)會拋出異常。如果是SPA(single page application)的話就會出現(xiàn)我前面那個故事一樣的結(jié)果——白屏。而且MDN還提供了一個可用性檢測的函數(shù),不過這里我要推薦的是另一個寫法:
function storageAvailable() {
try {
const mod = '__storage__test__'
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
}
基本概念
Web Storage提供了兩種機制讓我們實現(xiàn)離線存儲:
- localStorage
- sessionStorage
其中,sessionStorage會存儲數(shù)據(jù),直到瀏覽器關(guān)閉才銷毀數(shù)據(jù)。而localStorage則是持久式存儲。
另外需要注意的是,兩種機制都是在每個獨立域名下分開獨立存儲數(shù)據(jù)的。也就是瀏覽器的同源策略(相同協(xié)議;相同域名;相同端口)
意思就是,在a.com下無法訪問到b.com的storage數(shù)據(jù),當然這是基于安全性的考慮。
跨域
跨域是前端開發(fā)(面試)常遇到的問題。說到這個本人就好苦惱了,因為實際開發(fā)遇到的跨域問題,受到各種(后端)限制,通常簡單地使用Access-Control-Allow-origin解決。因此跨域的問題真心沒什么總結(jié)和心得,只能強行看人家的心得,來再次吸收與總結(jié)了。
由于同源策略的限制,相同主域名,不同子域名的頁面的storage都不能互相訪問,因此要實現(xiàn)跨域訪問的話,就必須采用其他的辦法,比如HTML5提出的postMessage方法:
首先設(shè)置一個控制中心hub,負責(zé)寫入/讀?。瘎h除 storage。其他要相互交互的域名就都通過iframe引入這個hub,通過postMessage和hub交互,達到讀寫storage的目的。參考annn.me的流程圖如下:
github上已有一個比較完備的類庫可以參考:cross-storage