Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
做項目的過程中,我們經常遇到需要把信息存儲在本地的情況,比如權限驗證的token、用戶信息、埋點計數、客戶配置的皮膚信息或語言種類等,我們可以暫存一下避免瀏覽器不必要的請求和客戶多余操作,給客戶使用帶來方便。
上一篇講了JavaScript瀏覽器端數據存儲方案之Cookie篇,這篇文章主要介紹localStorage和sessionStorage。
HTML5中 Web Storage 的出現,主要是為了彌補使用 Cookie 作為本地存儲的不足。Cookie 存儲的數據量非常小,而且數據會自動攜帶到請求頭里,但服務器端可能并不關心這些數據,所以會造成帶寬的浪費。
Web Storage 提供了兩個存儲對象:localStorage 和 sessionStorage。
sessionStorage 存儲的數據僅在本次會話有用,會話結束后會自動失效,而且數據僅在當前窗口有效,同一源下新窗口也訪問不到其他窗口基于sessionStorage 存儲的數據。也是由于這些特性,導致 sessionStorage 的使用場景會比較少。
localStorage 可以永久存儲,而且同源下數據多窗口也能共享。看起來很美好,但 localStorage 也有短板,絕大多數瀏覽器有 5M 的大小限制。但是這不足以成為大家使用 localStorage 的障礙,要知道 Cookie 只有 4K 的大小,多了一千多倍
localStorage 的基本使用
localStorage.setItem("b","isaac");//設置b為"isaac" var b=localStorage.getItem("b");//獲取b的值,為"isaac" var a=localStorage.key(0); // 獲取第0個數據項的鍵名,此處即為“b” localStorage.removeItem("b");//清除c的值 localStorage.clear();//清除當前域名下的所有localstorage數據
這里和大家分享一段我們在VUE項目中封裝使用的localStorage,大家可以借鑒實現的思路
有兩點需要注意一下。在 setItem 時,可能會達到大小限制,最好加上錯誤捕捉
另外在存儲容量快滿時,會造成 getItem 性能急劇下降。我們下面看看 localStorage 有哪些腦洞大開的用法
緩存靜態文件
你不禁要問,HTTP 協議不是本來就支持緩存文件嗎,為什么還要使用 localStorage 來緩存?為了可編程化,通俗一點說就是把命運握在自己手中。
HTTP 協議的緩存,可以由用戶瀏覽器清除或禁用緩存,也可以由 Web 服務器設置過期時間或不緩存。對于前端工程師,這更像是一個黑盒,想要決定文件是訪問緩存還是訪問遠程顯得有些力不從心了。
使用 localStorage 控制文件緩存的方式有兩種:
這兩種方式一般都會提前做好緩存過期策略,通常是使用版本號來控制,下面還會細講。否則文件新版上線,用戶客戶端還是舊版,這就麻煩大了,而且這類問題,還不好調試不好重現。
使用 Loader 加載靜態文件
由于請求都是動態發出的,所以可以對請求攔截處理。大致流程如下:
這個方式有個開源庫:basket.js(可以在github上訪問)
借助服務器端將靜態文件 inline 化
這個方式比上面那種更進一步,在第一次響應時把需要放入 localStorage 的文件都內聯進 html 中,后面每次響應只要文件版本沒有變化,都是渲染一段從 localStorage 加載該文件的代碼。這樣做的好處是可以有效減少請求次數,即使是第一次。
版本號不匹配(版本號可記在 Cookie 中,第一次訪問沒有版本號),服務端響應內容:
<script> function script2ls(id) { var script=document.getElementById(id); if (script) { localStorage[id]=script.innerHTML; } } </script> <script id="jquery.js">...jquery source code...</script> <script>script2ls('jquery.js')</script>
版本號匹配,服務端響應內容:
<script> function ls2script(id) { var script=document.createElement('script'); script.text=localStorage[id]; document.head.appendChild(script); } </script> <script>ls2script('jquery.js')</script>
不過使用 localStorage 緩存文件會有 XSS 的風險,而且造成的傷害可能是永久的
同源窗口通信
你可能不禁又要問,不是有 postMessage 嗎?沒錯 postMessage 確實可以用于窗口或 iframe 間通信,但是前提是你必須拿到打開新窗或 iframe 的句柄對象:
var popup=window.open(...popup details...); popup.postMessage("hello there!", "http://example.com");
這樣在新窗中再打開新窗,似乎就不好傳遞消息了。
你可能還想問,為什么要在窗口間通信?好問題,沒有應用場景的技術都是耍流氓。像多窗口共用的一些組件,而且對數據實時同步都有較高要求的都會是這個技術的應用場景。比如通知中心上面的未讀數量,兩個窗口,A 窗口更新為 8,切到 B 窗口還是 9,這就造成了體驗不一致,這個例子可能還覺得無關痛癢;再比如購物車,兩個產品窗口,A 窗口添加到購物車,切到 B 窗口添加到購物車,發現沒有 A 添加的產品,這樣就比較嚴重了。這當然也可以通過每個窗口都與后臺建立連接來更新,但用戶如果開十幾個窗口就開銷大了。
有了同源窗口通信,我們就可以只有一個窗口與后臺建立連接,收到更新后,廣播給其他窗口就可以。說了這么多,實現原理是怎樣的呢?
其實原理也簡單,每次 localStorage 中有任何變動都會觸發一個 storage 事件,所有窗口都監聽這個事件,一旦有窗口更新 localStorage,其他窗口都會收到通知,根據事件中的 key 把不關心的變動過濾掉。原理是很簡單,但是要實現一套完整的廣播機制還是有些復雜,你需要:
不用擔心,已經有了不錯的開源實現:diy/intercom.js、tejacques/crosstab
作為前端 DB 的存儲介質
你可能不滿足于用鍵值對保存數據,你還想保存更復雜的數據結構。
靈活存取 json 格式的數據:typicode/lowdb
通過 sql 對數據 CURD 操作:agershun/alasql
表單自動持久化
在填寫表單時,遇到瀏覽器奔潰或者誤操作導致填寫內容丟失,此刻用戶的內心也應該是奔潰的。誤操作還可以加一個 beforeunload 事件,在關閉瀏覽器或跳出當前頁前提醒一下用戶。那瀏覽器崩潰呢,將數據變更實時保存到后臺,這樣似乎開銷很大,實時保存到 localStorage 是個不錯的解決方案,真巧,也有一個開源實現:simsalabim/sisyphus
ebStorage的目的是克服由cookie所帶來的一些限制,當數據需要被嚴格控制在客戶端時,不需要持續的將數據發回服務器。
WebStorage兩個主要目標:
(1)提供一種在cookie之外存儲會話數據的路徑。
(2)提供一種存儲大量可以跨會話存在的數據的機制。
web存儲更加安全與快速,這些數據還不會保存到服務器,還可以存儲大量數據而不影響網站性能。
不管是 localStorage 還是 sessionStorage 使用方法都是一樣的語法,對常見操作語法進行示范。以下就以localStorage為例:
常見操作語法:
localStorage.key=value
localStorage.setItem(key,value)
localStorage.key
localStorage.getItem(key)
localStorage.removeItem(key)
delete localStorage.key
數據都是以鍵值對形式存在的,操作的時候與json有點類似。
應用1:取出本地存儲的所有數據,以localStorage為例。
localStorage和sessionStorage是兩個對象,類似json。可遍歷取出數據,如:
localStorage.user="倩倩"
localStorage.age="18"
localStorage.job="打雜"
console.log(localStorage)// {job: "打雜", age: "18", user: "倩倩", length: 3}
for(key in localStorage){
console.log(`${key}--${localStorage[key]}`)
}
運行程序之后,結果如圖:
我們發現遍歷的時候把localStorage的屬性和方法全部打印出來了,而我們需要的只是我們存儲的三個數據,其余的都不要,此時我們換個方法。
localStorage.user="倩倩"
localStorage.age="18"
localStorage.job="打雜"
console.log(localStorage)// {job: "打雜", age: "18", user: "倩倩", length: 3}
for(let i=0;i<localStorage.length;i++){
let key=localStorage.key(i)
console.log(`${key}:${localStorage[key]}`)
}
此時運行結果就是我們需要的結果了!
記住用戶登錄信息、存草稿、存郵件等經常會使用 localStorage,我們介紹下幾種存儲方式的區別,可以更好地根據需求選擇存儲方式。
cookies 和 sessionStorage、localStorage區別如圖:
上述看三者存儲大小有很大差異,存儲內容上也不同,cookie只能保存字符串類型,但sessionStorage和localStorage能夠支持任何類型的對象存儲。如果保存復雜json數據時,可以轉成字符串保存,取出時通過JSON.parse()轉成json格式。
安全性方面,web 存儲不會發送到服務器端,不用擔心被截獲,所以相對cookie安全些。
實例:網頁中寫信,自動保存草稿,網頁關閉重新打開之后數據依舊存在。
<textarea name="" id="email" cols="30" rows="10" oninput="save()"></textarea>
<script>
function save(){
var x=document.getElementById("email")
localStorage.setItem('email',x.value)
}
window.onload=function(){
var x=document.getElementById("email")
x.value=localStorage.getItem("email")
}
</script>
注意:如果你是直接使用瀏覽器打開html文件,此時發現并不會存儲,需要聲明下存儲是針對域的,所以我們需要放到服務內,服務內訪問才可以進行緩存。
需要的同學自己去下載個nginx。
TML本地存儲有cookies、 localStorage 、sessionStorage、Web SQL、IndexedDB。
以下是它們的區別
*請認真填寫需求信息,我們會在24小時內與您取得聯系。