整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          JavaScript瀏覽器端數(shù)據(jù)存儲(chǔ)方案之Web S

          JavaScript瀏覽器端數(shù)據(jù)存儲(chǔ)方案之Web Storage篇

          做項(xiàng)目的過程中,我們經(jīng)常遇到需要把信息存儲(chǔ)在本地的情況,比如權(quán)限驗(yàn)證的token、用戶信息、埋點(diǎn)計(jì)數(shù)、客戶配置的皮膚信息或語言種類等,我們可以暫存一下避免瀏覽器不必要的請(qǐng)求和客戶多余操作,給客戶使用帶來方便。

          上一篇講了JavaScript瀏覽器端數(shù)據(jù)存儲(chǔ)方案之Cookie篇,這篇文章主要介紹localStorage和sessionStorage。

          HTML5中 Web Storage 的出現(xiàn),主要是為了彌補(bǔ)使用 Cookie 作為本地存儲(chǔ)的不足。Cookie 存儲(chǔ)的數(shù)據(jù)量非常小,而且數(shù)據(jù)會(huì)自動(dòng)攜帶到請(qǐng)求頭里,但服務(wù)器端可能并不關(guān)心這些數(shù)據(jù),所以會(huì)造成帶寬的浪費(fèi)。

          Web Storage 提供了兩個(gè)存儲(chǔ)對(duì)象:localStorage 和 sessionStorage。

          sessionStorage 存儲(chǔ)的數(shù)據(jù)僅在本次會(huì)話有用,會(huì)話結(jié)束后會(huì)自動(dòng)失效,而且數(shù)據(jù)僅在當(dāng)前窗口有效,同一源下新窗口也訪問不到其他窗口基于sessionStorage 存儲(chǔ)的數(shù)據(jù)。也是由于這些特性,導(dǎo)致 sessionStorage 的使用場景會(huì)比較少。

          localStorage 可以永久存儲(chǔ),而且同源下數(shù)據(jù)多窗口也能共享??雌饋砗苊篮茫?localStorage 也有短板,絕大多數(shù)瀏覽器有 5M 的大小限制。但是這不足以成為大家使用 localStorage 的障礙,要知道 Cookie 只有 4K 的大小,多了一千多倍

          localStorage 的基本使用

          localStorage.setItem("b","isaac");//設(shè)置b為"isaac"
          var b=localStorage.getItem("b");//獲取b的值,為"isaac"
          var a=localStorage.key(0); // 獲取第0個(gè)數(shù)據(jù)項(xiàng)的鍵名,此處即為“b”
          localStorage.removeItem("b");//清除c的值
          localStorage.clear();//清除當(dāng)前域名下的所有l(wèi)ocalstorage數(shù)據(jù)
          

          這里和大家分享一段我們?cè)赩UE項(xiàng)目中封裝使用的localStorage,大家可以借鑒實(shí)現(xiàn)的思路

          有兩點(diǎn)需要注意一下。在 setItem 時(shí),可能會(huì)達(dá)到大小限制,最好加上錯(cuò)誤捕捉

          另外在存儲(chǔ)容量快滿時(shí),會(huì)造成 getItem 性能急劇下降。我們下面看看 localStorage 有哪些腦洞大開的用法

          緩存靜態(tài)文件

          你不禁要問,HTTP 協(xié)議不是本來就支持緩存文件嗎,為什么還要使用 localStorage 來緩存?為了可編程化,通俗一點(diǎn)說就是把命運(yùn)握在自己手中。

          HTTP 協(xié)議的緩存,可以由用戶瀏覽器清除或禁用緩存,也可以由 Web 服務(wù)器設(shè)置過期時(shí)間或不緩存。對(duì)于前端工程師,這更像是一個(gè)黑盒,想要決定文件是訪問緩存還是訪問遠(yuǎn)程顯得有些力不從心了。

          使用 localStorage 控制文件緩存的方式有兩種:

          1. 使用 Loader 加載靜態(tài)文件
          2. 借助服務(wù)器端將靜態(tài)文件 inline 化

          這兩種方式一般都會(huì)提前做好緩存過期策略,通常是使用版本號(hào)來控制,下面還會(huì)細(xì)講。否則文件新版上線,用戶客戶端還是舊版,這就麻煩大了,而且這類問題,還不好調(diào)試不好重現(xiàn)。

          使用 Loader 加載靜態(tài)文件

          由于請(qǐng)求都是動(dòng)態(tài)發(fā)出的,所以可以對(duì)請(qǐng)求攔截處理。大致流程如下:

          1. 查看請(qǐng)求的文件 url 是否有緩存到 localStorage
          2. 如果沒有,到第 2 大步
          3. 如果有,判斷文件是否過期或版本號(hào)是否匹配
          4. 過期或不匹配,到第 2 大步
          5. 文件內(nèi)容有效,到第 4 大步
          6. 請(qǐng)求遠(yuǎn)程文件
          7. 緩存最新文件內(nèi)容
          8. 執(zhí)行文件內(nèi)容

          這個(gè)方式有個(gè)開源庫:basket.js(可以在github上訪問)

          借助服務(wù)器端將靜態(tài)文件 inline 化

          這個(gè)方式比上面那種更進(jìn)一步,在第一次響應(yīng)時(shí)把需要放入 localStorage 的文件都內(nèi)聯(lián)進(jìn) html 中,后面每次響應(yīng)只要文件版本沒有變化,都是渲染一段從 localStorage 加載該文件的代碼。這樣做的好處是可以有效減少請(qǐng)求次數(shù),即使是第一次。

          版本號(hào)不匹配(版本號(hào)可記在 Cookie 中,第一次訪問沒有版本號(hào)),服務(wù)端響應(yīng)內(nèi)容:

          <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> 
          

          版本號(hào)匹配,服務(wù)端響應(yīng)內(nèi)容:

          <script> 
          function ls2script(id) { 
           var script=document.createElement('script');
           script.text=localStorage[id];
           document.head.appendChild(script);
          }
          </script>
          <script>ls2script('jquery.js')</script> 
          

          不過使用 localStorage 緩存文件會(huì)有 XSS 的風(fēng)險(xiǎn),而且造成的傷害可能是永久的

          同源窗口通信

          你可能不禁又要問,不是有 postMessage 嗎?沒錯(cuò) postMessage 確實(shí)可以用于窗口或 iframe 間通信,但是前提是你必須拿到打開新窗或 iframe 的句柄對(duì)象:

          var popup=window.open(...popup details...); 
          popup.postMessage("hello there!", "http://example.com"); 
          

          這樣在新窗中再打開新窗,似乎就不好傳遞消息了。

          你可能還想問,為什么要在窗口間通信?好問題,沒有應(yīng)用場景的技術(shù)都是耍流氓。像多窗口共用的一些組件,而且對(duì)數(shù)據(jù)實(shí)時(shí)同步都有較高要求的都會(huì)是這個(gè)技術(shù)的應(yīng)用場景。比如通知中心上面的未讀數(shù)量,兩個(gè)窗口,A 窗口更新為 8,切到 B 窗口還是 9,這就造成了體驗(yàn)不一致,這個(gè)例子可能還覺得無關(guān)痛癢;再比如購物車,兩個(gè)產(chǎn)品窗口,A 窗口添加到購物車,切到 B 窗口添加到購物車,發(fā)現(xiàn)沒有 A 添加的產(chǎn)品,這樣就比較嚴(yán)重了。這當(dāng)然也可以通過每個(gè)窗口都與后臺(tái)建立連接來更新,但用戶如果開十幾個(gè)窗口就開銷大了。

          有了同源窗口通信,我們就可以只有一個(gè)窗口與后臺(tái)建立連接,收到更新后,廣播給其他窗口就可以。說了這么多,實(shí)現(xiàn)原理是怎樣的呢?

          其實(shí)原理也簡單,每次 localStorage 中有任何變動(dòng)都會(huì)觸發(fā)一個(gè) storage 事件,所有窗口都監(jiān)聽這個(gè)事件,一旦有窗口更新 localStorage,其他窗口都會(huì)收到通知,根據(jù)事件中的 key 把不關(guān)心的變動(dòng)過濾掉。原理是很簡單,但是要實(shí)現(xiàn)一套完整的廣播機(jī)制還是有些復(fù)雜,你需要:

          • 管理好每個(gè)窗口的唯一 ID
          • 防止消息重復(fù)
          • 防止消息發(fā)給不關(guān)心的窗口
          • 窗口心跳 keep alive
          • 主窗口選舉
          • ...

          不用擔(dān)心,已經(jīng)有了不錯(cuò)的開源實(shí)現(xiàn):diy/intercom.js、tejacques/crosstab

          作為前端 DB 的存儲(chǔ)介質(zhì)

          你可能不滿足于用鍵值對(duì)保存數(shù)據(jù),你還想保存更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。

          靈活存取 json 格式的數(shù)據(jù):typicode/lowdb

          通過 sql 對(duì)數(shù)據(jù) CURD 操作:agershun/alasql

          表單自動(dòng)持久化

          在填寫表單時(shí),遇到瀏覽器奔潰或者誤操作導(dǎo)致填寫內(nèi)容丟失,此刻用戶的內(nèi)心也應(yīng)該是奔潰的。誤操作還可以加一個(gè) beforeunload 事件,在關(guān)閉瀏覽器或跳出當(dāng)前頁前提醒一下用戶。那瀏覽器崩潰呢,將數(shù)據(jù)變更實(shí)時(shí)保存到后臺(tái),這樣似乎開銷很大,實(shí)時(shí)保存到 localStorage 是個(gè)不錯(cuò)的解決方案,真巧,也有一個(gè)開源實(shí)現(xiàn):simsalabim/sisyphus

          ebStorage的目的是克服由cookie所帶來的一些限制,當(dāng)數(shù)據(jù)需要被嚴(yán)格控制在客戶端時(shí),不需要持續(xù)的將數(shù)據(jù)發(fā)回服務(wù)器。

          WebStorage兩個(gè)主要目標(biāo):

          (1)提供一種在cookie之外存儲(chǔ)會(huì)話數(shù)據(jù)的路徑。

          (2)提供一種存儲(chǔ)大量可以跨會(huì)話存在的數(shù)據(jù)的機(jī)制。

          web存儲(chǔ)更加安全與快速,這些數(shù)據(jù)還不會(huì)保存到服務(wù)器,還可以存儲(chǔ)大量數(shù)據(jù)而不影響網(wǎng)站性能。

          web 存儲(chǔ)類型

          1. localStorage - 用于長久保存數(shù)據(jù),沒有有效期,直到手動(dòng)清除。
          2. sessionStorage - 臨時(shí)保存當(dāng)前窗口的數(shù)據(jù),窗口關(guān)閉之后自動(dòng)清除。

          不管是 localStorage 還是 sessionStorage 使用方法都是一樣的語法,對(duì)常見操作語法進(jìn)行示范。以下就以localStorage為例:

          常見操作語法:

          • 保存數(shù)據(jù):

          localStorage.key=value

          localStorage.setItem(key,value)

          • 獲取數(shù)據(jù)

          localStorage.key

          localStorage.getItem(key)

          • 刪除單個(gè)數(shù)據(jù):

          localStorage.removeItem(key)

          delete localStorage.key

          • 刪除全部:localStorage.clear()
          • 獲取某個(gè)索引的鍵值:localStorage.key(index)

          數(shù)據(jù)都是以鍵值對(duì)形式存在的,操作的時(shí)候與json有點(diǎn)類似。

          web存儲(chǔ)數(shù)據(jù)應(yīng)用

          應(yīng)用1:取出本地存儲(chǔ)的所有數(shù)據(jù),以localStorage為例。

          localStorage和sessionStorage是兩個(gè)對(duì)象,類似json??杀闅v取出數(shù)據(jù),如:

          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]}`)
          }

          運(yùn)行程序之后,結(jié)果如圖:


          我們發(fā)現(xiàn)遍歷的時(shí)候把localStorage的屬性和方法全部打印出來了,而我們需要的只是我們存儲(chǔ)的三個(gè)數(shù)據(jù),其余的都不要,此時(shí)我們換個(gè)方法。

          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]}`)
          }

          此時(shí)運(yùn)行結(jié)果就是我們需要的結(jié)果了!

          記住用戶登錄信息、存草稿、存郵件等經(jīng)常會(huì)使用 localStorage,我們介紹下幾種存儲(chǔ)方式的區(qū)別,可以更好地根據(jù)需求選擇存儲(chǔ)方式。

          幾種存儲(chǔ)方式區(qū)別

          cookies 和 sessionStorage、localStorage區(qū)別如圖:

          上述看三者存儲(chǔ)大小有很大差異,存儲(chǔ)內(nèi)容上也不同,cookie只能保存字符串類型,但sessionStorage和localStorage能夠支持任何類型的對(duì)象存儲(chǔ)。如果保存復(fù)雜json數(shù)據(jù)時(shí),可以轉(zhuǎn)成字符串保存,取出時(shí)通過JSON.parse()轉(zhuǎn)成json格式。

          安全性方面,web 存儲(chǔ)不會(huì)發(fā)送到服務(wù)器端,不用擔(dān)心被截獲,所以相對(duì)cookie安全些。

          實(shí)例:網(wǎng)頁中寫信,自動(dòng)保存草稿,網(wǎng)頁關(guān)閉重新打開之后數(shù)據(jù)依舊存在。

          <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文件,此時(shí)發(fā)現(xiàn)并不會(huì)存儲(chǔ),需要聲明下存儲(chǔ)是針對(duì)域的,所以我們需要放到服務(wù)內(nèi),服務(wù)內(nèi)訪問才可以進(jìn)行緩存。

          需要的同學(xué)自己去下載個(gè)nginx。

          TML本地存儲(chǔ)有cookies、 localStorage 、sessionStorage、Web SQL、IndexedDB。

          以下是它們的區(qū)別

          1. cookies: 在HTML5標(biāo)準(zhǔn)前本地儲(chǔ)存的主要方式,優(yōu)點(diǎn)是兼容性好,請(qǐng)求頭自帶cookie方便,缺點(diǎn)是大小只有4k,自動(dòng)請(qǐng)求頭加入cookie浪費(fèi)流量,每個(gè)domain限制20個(gè)cookie,使用起來麻煩需要自行封裝
          2. localStorage:HTML5加入的以鍵值對(duì)(Key-Value)為標(biāo)準(zhǔn)的方式,優(yōu)點(diǎn)是操作方便,永久性儲(chǔ)存(除非手動(dòng)刪除),大小為5M,兼容IE8+
          3. sessionStorage:與localStorage基本類似,區(qū)別是sessionStorage當(dāng)頁面關(guān)閉后會(huì)被清理,而且與cookie、localStorage不同,他不能在所有同源窗口中共享,是會(huì)話級(jí)別的儲(chǔ)存方式
          4. Web SQL:2010年被W3C廢棄的本地?cái)?shù)據(jù)庫數(shù)據(jù)存儲(chǔ)方案,但是主流瀏覽器(火狐除外)都已經(jīng)有了相關(guān)的實(shí)現(xiàn),web sql類似于SQLite,是真正意義上的關(guān)系型數(shù)據(jù)庫,用sql進(jìn)行操作,當(dāng)我們用JavaScript時(shí)要進(jìn)行轉(zhuǎn)換,較為繁瑣。
          5. IndexedDB: 是被正式納入HTML5標(biāo)準(zhǔn)的數(shù)據(jù)庫儲(chǔ)存方案,它是NoSQL數(shù)據(jù)庫,用鍵值對(duì)進(jìn)行儲(chǔ)存,可以進(jìn)行快速讀取操作,非常適合web場景,同時(shí)用JavaScript進(jìn)行操作會(huì)非常方便。

          主站蜘蛛池模板: 精品日产一区二区三区手机| 熟女少妇丰满一区二区| 天码av无码一区二区三区四区 | 一区二区日韩国产精品| 亚洲熟妇av一区二区三区下载| 无码精品人妻一区二区三区免费 | 福利电影一区二区| 免费精品一区二区三区在线观看| 久久精品国产一区| 日本高清不卡一区| 精品视频一区二区三区免费| 国产情侣一区二区三区| 亚洲av高清在线观看一区二区 | 日韩精品无码视频一区二区蜜桃| 国产成人精品一区二三区| 日韩视频一区二区| 亚洲午夜精品一区二区麻豆 | 无码精品黑人一区二区三区 | 午夜一区二区免费视频| 在线视频亚洲一区| 无码AV一区二区三区无码 | 性色A码一区二区三区天美传媒| 一区二区三区人妻无码| 久久精品一区二区三区四区 | 日本精品一区二区三区在线视频| 日本免费一区尤物| 亚洲AV日韩精品一区二区三区| 极品少妇伦理一区二区| 国产在线精品一区二区夜色| 国产内射999视频一区| 久久久久人妻一区二区三区vr| 国产高清一区二区三区| 无码日本电影一区二区网站| 日韩AV无码一区二区三区不卡 | 亚洲国产专区一区| 无码人妻AV免费一区二区三区| 成人精品一区二区户外勾搭野战| 日韩视频一区二区在线观看| 久久精品中文字幕一区| 69福利视频一区二区| 国产一区二区三区在线|