<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文由轉轉技術團隊劉筱雨分享,原題“一文讀懂瀏覽器本地存儲:Web Storage”,下文進行了排版和內容優化。

    1、引言

    鑒于目前瀏覽器技術的進步(主要是HTML5的普及),在Web網頁端IM聊天應用的技術選型階段,很多開發者都會糾結到底該不該像原生移動端IM那樣將聊天記錄緩存在瀏覽器的本地,還是像傳統Web端即時通訊那樣繼續存儲在服務端?本文將為你簡潔明了地講清楚瀏覽器本地存儲技術(Web Storage),然后你就知道到底該怎么選擇了。

    瀏覽器本地存儲是指瀏覽器提供的一種機制,允許 Web 應用程序在瀏覽器端存儲數據,以便在用戶下次訪問時可以快速獲取和使用這些數據。一共兩種存儲方式:localStorage 和 sessionStorage,本文將主要圍繞這兩種技術來進行總結。

     

    2、初識瀏覽器本地存儲(localStorage和sessionStorage)

    2.1區別

    localStorage 和 sessionStorage 的主要區別是生命周期。

    具體區別如下:

    容量限制的目的是防止濫用本地存儲空間,導致用戶瀏覽器變慢。

    2.2瀏覽器兼容性

    1)現在的瀏覽器基本上都是支持這兩種 Storage 特性的。

    各瀏覽器支持版本如下:

    2)如果使用的是老式瀏覽器,比如Internet Explorer 6、7 或者其他,就需要在使用前檢測瀏覽器是否支持本地存儲或者是否被禁用。

    以 localStorage 為例:

    if(window.localStorage){

      alert("瀏覽器支持 localStorage");

    } else {

      alert("瀏覽器不支持 localStorage");

    }

    3)某些瀏覽器版本使用過程中,會出現 Storage 不能正常使用的情況,記得添加 try/catch。

    以 localStorage 為例:

    if(window.localStorage){

      try {

        localStorage.setItem("username", "name");

        alert("瀏覽器支持 localStorage");

      } catch (e) {

        alert("瀏覽器支持 localStorage 后不可使用");

      }

    } else {

      alert("瀏覽器不支持 localStorage");

    }

    3、基本用法演示

    3.1 基本API

    localStorage 和 sessionStorage 提供了相同的方法進行存儲、檢索和刪除。

    常用的方法如下:

    1)設置數據:setItem(key, value)。存儲的值可以是字符串、數字、布爾、數組和對象。對象和數組必須轉換為 string 進行存儲。JSON.parse() 和 JSON.stringify() 方法可以將數組、對象等值類型轉換為字符串類型,從而存儲到 Storage 中(示例代碼如下)。

    localStorage.setItem("username", "name"); // "name"

    localStorage.setItem("count", 1); // "1"

    localStorage.setItem("isOnline", true); // "true"

    sessionStorage.setItem("username", "name");

    // user 存儲時,先使用 JSON 序列化,否則保存的是[object Object]

    const user = { "username": "name" };

    localStorage.setItem("user", JSON.stringify(user));

    sessionStorage.setItem("user", JSON.stringify(user));

    eg:數據沒有序列化,導致保存的數據異常:

    2)獲取數據:getItem(key)。如果 key 對應的 value 獲取不到,則返回值是 null。

    const usernameLocal = localStorage.getItem("username");

    const usernameSession = sessionStorage.getItem("username");

    // 獲取到的數據為string,使用時反序列化數據

    const userLocal = JSON.parse(localStorage.getItem("user"));

    const userSession = JSON.parse(sessionStorage.getItem("user"));

    3)刪除數據:removeItem(key);

    localStorage.removeItem("username");

    sessionStorage.removeItem("username");

    4)清空數據:clear();

    localStorage.clear();

    sessionStorage.clear();

    5)在不確定是否存在 key 的情況下,可以使用 hasOwnProperty() 進行檢查;

    localStorage.hasOwnProperty("userName"); // true

    sessionStorage.hasOwnProperty("userName"); // false

    6)當然,也可以使用 Object.keys() 查看所有存儲數據的鍵;

    Object.keys(localStorage); // ['username']

    Object.keys(sessionStorage);

    3.2 瀏覽器查看

    本地存儲的內容可以在瀏覽器中直接查看,以 Chrome 為例,按住鍵盤 F12 進入開發者工具后,選擇 Application,然后就能在左邊 Storage 列表中找到 localStorage 和 sessionStorgae。

    3.3 監聽數據變化

    當存儲的數據發生變化時,其他頁面通過監聽 storage 事件,來獲取變更前后的值,以及根據值的變化來處理頁面的展示邏輯。

    JS 原生監聽事件,只能夠監聽同源非同一個頁面中的 storage 事件,如果想監聽同一個頁面的,需要改寫原生方法,拋出自定義事件來監聽。

    具體如下:

    1)監聽同源非同一個頁面:

    直接在其他頁面添加監聽事件即可。

    eg:同域下的 A、B 兩個頁面,A 修改了 localStorage,B 頁面可以監聽到 storage 事件。

    window.addEventListener("storage", () => {

      // 監聽 username 值變化

      if (e.key === "username") {

        console.log("username 舊值:" + e.oldValue + ",新值:" + e.newValue);

      }

    })

    注:

    • 1)當兩次 setItem 更新的值一樣時,監聽方法是不會觸發的;
    • 2)storage 事件只能監聽到 localStorage 的變化。

    2)監聽同一個頁面:

    重寫 Storage 的 setItem 事件,同理,也可以監聽刪除事件 removeItem 和獲取事件 getItem。

    (() => {

      const originalSetItem = localStorage.setItem;

      // 重寫 setItem 函數

      localStorage.setItem = function (key, val) {

        let event = new Event("setItemEvent");

        event.key = key;

        event.newValue = val;

        window.dispatchEvent(event);

        originalSetItem.apply(this, arguments);

      };

    })();

    window.addEventListener("setItemEvent", function (e) {

      // 監聽 username 值變化

      if (e.key === "username") {

        const oldValue = localStorage.getItem(e.key);

        console.log("username 舊值:" + oldValue + ",新值:" + e.newValue);

      }

    });

    4、存儲容量上限到底是不是5MB?

    瀏覽器默認能夠存儲 5M 的數據,但實際上,瀏覽器并不會為其分配特定的存儲空間,而是根據當前瀏覽器的空閑空間來判斷能夠分配多少存儲空間。

    可以使用 Storage 的 length 屬性,對存儲容量進行測算。

    以 localStorage 為例:

    let str = "0123456789";

    let temp = "";

    // 先生成一個 10KB 的字符串

    while (str.length !== 10240) {

      str = str + "0123456789";

    }

    // 清空

    localStorage.clear();

    // 計算總量

    const computedTotal = () => {

      return new Promise((resolve) => {

        // 往 localStorage 中累積存儲 10KB

        const timer = setInterval(() => {

          try {

            localStorage.setItem("temp", temp);

          } catch (e) {

            // 報錯說明超出最大存儲

            resolve(temp.length / 1024);

            clearInterval(timer);

            // 統計完記得清空

            localStorage.clear();

          }

          temp += str;

        }, 0);

      });

    };

    // 計算使用量

    const computedUse = () => {

      let cache = 0;

      for (let key in localStorage) {

        if (localStorage.hasOwnProperty(key)) {

          cache += localStorage.getItem(key).length;

        }

      }

      return (cache / 1024).toFixed(2);

    };

     

    (async () => {

      const total = await computedTotal();

      let use = "0123456789";

      for (let i = 0; i < 1000; i++) {

        use += "0123456789";

      }

      localStorage.setItem("use", use);

      const useCache = computedUse();

     

      console.log(`最大容量${total}KB`);

      console.log(`已用${useCache}KB`);

      console.log(`剩余可用容量${total - useCache}KB`);

    })();

    可見在 Chrome 瀏覽器下,localStorage 有 5M 容量:

    5、用好本地存儲的一些建議

    在某些特殊場景下,需要存儲大數據,為了更好的利用 Storage 的存儲空間,可以采取以下解決方案,但不應該過于頻繁地將大量數據存儲在 Storage 中,因為在寫入數據時,會對整個頁面進行阻塞(不推薦這種方式)。

    5.1壓縮數據

    可以使用數據壓縮庫對 Storage 中的數據進行壓縮,從而減小數據占用的存儲空間。

    eg:使用 lz-string 庫的 compress() 函數將數據進行壓縮,并將壓縮后的數據存儲到 localStorage 中。

    const LZString = require("lz-string");

    const data = "This is a test message";

    // 壓縮

    const compressedData = LZString.compress(data);

    localStorage.setItem("test", compressedData);

    // 解壓

    const decompressedData = LZString.decompress(localStorage.getItem("test"));

    5.2分割數據

    將大的數據分割成多個小的片段存儲到 Storage 中,從而減小單個數據占用的存儲空間。

    eg:將用戶數據分割為單項存儲到 localStorage 中。

    for (const key in userInfo) {

      localStorage.setItem(key, userInfo[key]);

    }

    5.3取消不必要的數據存儲

    可以在代碼中取消一些不必要的數據存儲,從而減小占用空間。

    eg:只存儲用到的用戶名、公司主體和后端所在環境字段信息。

    for (const key in userInfo) {

      if (["userName", "legalEntityName", "isOnline"].includes(key)) {

        localStorage.setItem(key, userInfo[key]);

      }

    }

    5.4設置過期時間

    localStorage 是不支持過期時間的,在存儲信息過多后,會拖慢瀏覽器速度,也會因為瀏覽器存儲容量不夠而報錯,可以封裝一層邏輯來實現設置過期時間,以達到清理的目的。

    // 設置

    function set(key, value){

      const time = new Date().getTime(); //獲取當前時間

      localStorage.setItem(key, JSON.stringify({value, time})); //轉換成json字符串

    }

    // 獲取

    function get(key, exp){

      // exp 過期時間

      const value = localStorage.getItem(key);

      const valueJson = JSON.parse(value);

      //當前時間 - 存儲的創建時間 > 過期時間

      if(new Date().getTime() - valueJson.time > exp){

        console.log("expires"); //提示過期

      } else {

        console.log("value:" + valueJson.value);

      }

    }

    6、實踐應用中的案例參考

    6.1 使用習慣記錄

    用來緩存一些篩選項數據,保存用戶習慣信息,起到避免多次重復操作的作用。

    eg:在 beetle 工程列表中,展示了自已權限下所有 beetle 的項目,對于參與項目多和參與項目少的人,操作習慣是不同的,由此,記錄收藏功能狀態解決了這一問題,讓篩選項記住用戶選擇,方便下次使用。

     

     

    在開發使用中,直接獲取 localStorage.getItem('isFavor') 作為默認值展示,切換后使用 localStorage.setItem() 方法更新保存內容。

    // 獲取

    const isFavor = localStorage.getItem('isFavor');

    this.state = {

      isFavor: isFavor !== null ? Number(isFavor) : EngineeringTypeEnum.FAVOR,

    };

    // 展示默認值

    <Form.Item name='isFavor' initialValue={this.state.isFavor}>

      <Select

        placeholder='篩選收藏的工程'

        onChange={(e) => this.changeFavor(e)}

        {...searchSmallFormProps}

      >

          {EngineeringTypeEnum.property.map(e => (<Option key={e.id} value={e.id}>{e.name}</Option>))}

      </Select>

    </Form.Item>

    // 變更

    changeFavor = (e) => {

      localStorage.setItem('isFavor', e);

      this.setState({ isFavor: e });

    };

    6.2 首次打開提示

    用來緩存用戶導覽,尤其是只需要出現一次的操作說明彈窗等。

    eg:當第一次或者清空緩存后登錄,頁面需要出現操作指南和用戶手冊的彈窗說明。

    在開發使用中,注意存儲的數據類型為 string,轉成布爾值是為了在插件中方便控制彈窗的顯示隱藏。

    // 獲取

    const operationVisible = localStorage.getItem('operationVisible');

    this.state = {

      operationVisible: operationVisible === null || operationVisible === 'true' ? true : false,

    };

    // 控制展示

    <Modal

      title='操作指南'

      open={this.state.operationVisible}

      onCancel={() => {

        this.setState({ operationVisible: false });

        localStorage.setItem('operationVisible', false);

      }}

      footer={null}

      destroyOnClose={true}

    >

      <Divider orientation='left'>動作</Divider>

      <p>接口 》 用例 》 用例集,3級結構滿足不了后續的使用,因此增加【動作】這一層級,【動作】是接口測試的最小單元,多個【動作】可以組合成一個用例,多個用例可以聚合為用例集;</p>

      <Image src={OperationGuidePng} preview={false} />

    </Modal>

    6.3 減少重復訪問接口

    在瀏覽頁面時,會遇到一些經常訪問但返回數據不更新的接口,這種特別適合用做頁面緩存,只在頁面打開的時候訪問一次,其他時間獲取緩存數據即可。

    eg:在我們的一些內部系統中,用戶信息是每個頁面都要用到的,尤其是 userId 字段,會與每個獲取數據接口掛鉤,但這個數據是不會變的,一直請求是沒有意義的,為減少接口的訪問次數,可以將主要數據緩存在 localStorage 內,方便其他接口獲取。

    7、本文小結

    希望通過此篇文章,可以讓大家了解 Web Storage 在瀏覽器數據存儲和讀取的相關操作,以及相關事件和限制。

    它可以用于保存用戶的偏好設置、表單數據等,在開發中使用可以方便的存儲和讀取數據,提高用戶體驗。當然,在使用時需要特別注意它的限制,以及在存儲、讀取和刪除數據過程中的錯誤處理。

    8、參考資料

    [1] 新手入門貼:史上最全Web端即時通訊技術原理詳解

    [2] Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE

    [3] 一文讀懂前端技術演進:盤點Web前端20年的技術變遷史

    [4] Web端即時通訊基礎知識補課:一文搞懂跨域的所有問題!

    [5] Web端即時通訊實踐干貨:如何讓你的WebSocket斷網重連更快速?

    [6] WebSocket從入門到精通,半小時就夠!

    [7] WebSocket硬核入門:200行代碼,教你徒手擼一個WebSocket服務器

    [8] 長連接網關技術專題(四):愛奇藝WebSocket實時推送網關技術實踐

    [9] 網頁端IM通信技術快速入門:短輪詢、長輪詢、SSE、WebSocket

    [10] 搞懂現代Web端即時通訊技術一文就夠:WebSocket、socket.io、SSE

    [11] IM跨平臺技術學習(一):快速了解新一代跨平臺桌面技術——Electron

    [12] Wasm在即時通訊IM場景下的Web端應用性能提升初探

    [13] 一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)

    [14] 一套億級用戶的IM架構技術干貨(上篇):整體架構、服務拆分等

    [15] 一套億級用戶的IM架構技術干貨(下篇):可靠性、有序性、弱網優化等

    [16] 從新手到專家:如何設計一套億級消息量的分布式IM系統

    [17] 新手入門一篇就夠:從零開發移動端IM


    (本文已同步發布于:http://www.52im.net/thread-4745-1-1.html



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: a拍拍男女免费看全片| 8090在线观看免费观看| 国产成人免费a在线视频app| 亚洲国产精品专区| 成年人网站免费视频| 亚洲一区在线免费观看| 最近中文字幕mv免费高清视频7| 亚洲区视频在线观看| 德国女人一级毛片免费| 亚洲色大情网站www| 国产精品色午夜免费视频| 国产亚洲精品精品精品| 亚洲AV无码成人精品区大在线| 国产精品美女久久久免费| 亚洲av无码精品网站| 在线视频精品免费| 亚洲av永久中文无码精品综合 | 美女视频黄.免费网址 | 免费视频专区一国产盗摄| 亚洲一区二区三区在线观看网站| 国产在线ts人妖免费视频| 国产乱子伦精品免费视频| 久久精品亚洲一区二区三区浴池 | 亚洲一区免费在线观看| 亚洲精品国产摄像头| 国产av无码专区亚洲国产精品 | 玖玖在线免费视频| 亚洲人成在线中文字幕| 免费99热在线观看| 国产拍拍拍无码视频免费| 亚洲中文字幕无码av在线| 免费看国产精品麻豆| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 国产99视频精品免费视频7| a色毛片免费视频| 四虎亚洲精品高清在线观看| 久久精品国产亚洲5555| 麻豆国产精品免费视频| 国产成人精品免费视频大全| 亚洲人成7777影视在线观看| www.亚洲精品|