自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

實(shí)現(xiàn)前端資源增量式更新的一種思路

開發(fā) 前端
“增量式更新”簡單地說就是在版本更新的時(shí)候不需要重新加載資源,只需要加載一段很小的 diff 信息,然后合并到當(dāng)前資源上,類似 git merge 的效果。

實(shí)現(xiàn)前端資源增量式更新的一種思路

之前校招面試的時(shí)候遇到過一個(gè)很有趣的問題:

“假設(shè)有一個(gè)超超超大型的Web項(xiàng)目,JS源代碼壓縮之后超過10MB(實(shí)際怎么可能會(huì)有這么大的嘛=。=),每次更新之后都需要用戶重新加載JS是不可接受的,那么怎么樣從工程的角度解決這種問題?”

一開始立馬想到了好幾點(diǎn)解決方案,比如:

  1. 抽出基礎(chǔ)的不常更新的模塊作為長期緩存;
  2. 如果使用了 React 或者 Vue2.0 這樣支持服務(wù)器端渲染的框架的話,就采用服務(wù)器端渲染然后再逐步分塊加載 JS 的方法;
  3. 如果是 Hybrid 開發(fā)的話,可以考慮使用本地資源加載,類似“離線包”的想法(之前在騰訊實(shí)習(xí)的時(shí)候天天遇到這東西)。

后來在面試官的引導(dǎo)下想到了一種“增量式更新”的解決方案,簡單地說就是在版本更新的時(shí)候不需要重新加載資源,只需要加載一段很小的 diff 信息,然后合并到當(dāng)前資源上,類似 git merge 的效果。

1、用戶端使用 LocalStorage 或者其它儲(chǔ)存方案,存儲(chǔ)一份原始代碼+時(shí)間戳:

  1.  
  2.     timeStamp"20161026xxxxxx"
  3.  
  4.     data: "aaabbbccc" 
  5.  
  6.  

2、每次加載資源的時(shí)候向服務(wù)器發(fā)送這個(gè)時(shí)間戳;

3、服務(wù)器從接受到時(shí)間戳中識(shí)別出客戶端的版本,和***的版本做一次 diff,返回兩者的 diff 信息:

  1. diff("aaabbbccc""aaagggccc"); 
  2.  
  3. // 假設(shè)我們的diff信息這樣表示: 
  4.  
  5. // [3, "-3""+ggg", 3]  

4、客戶端接收到這個(gè) diff 信息之后,把本地資源和時(shí)間戳更新到***,實(shí)現(xiàn)一次增量更新:

  1. mergeDiff("aaabbbccc", [3, "-3""+ggg", 3]); 
  2.  
  3. //=> "aaagggccc"  

實(shí)踐

下面把這個(gè)方案中的核心思想實(shí)現(xiàn)一遍,簡單地說就是實(shí)現(xiàn) diff 和 mergeDiff 兩個(gè)函數(shù)。

今天找到了一個(gè)不錯(cuò)的 diff 算法:

GitHub – kpdecker/jsdiff: A javascript text differencing implementation.

我們只需要調(diào)用它的 diffChars 方法來對比兩個(gè)字符串的差異:

  1. var oldStr = 'aaabbbccc'
  2.  
  3. var newStr = 'aaagggccc'
  4.  
  5. JsDiff.diffChars(oldStr, newStr); 
  6.  
  7. //=> 
  8.  
  9. //[ { count: 3, value: 'aaa' }, 
  10.  
  11. //  { count: 3, added: undefined, removed: true, value: 'bbb' }, 
  12.  
  13. //  { count: 3, added: true, removed: undefined, value: 'ggg' }, 
  14.  
  15. //  { count: 3, value: 'ccc' } ]  

上面的 diff 信息略有些冗余,我們可以自定義一種更簡潔的表示方法來加速傳輸?shù)乃俣龋?/p>

  1. [3, "-3""+ggg", 3] 

整數(shù)代表無變化的字符數(shù)量,“-”開頭的字符串代表被移除的字符數(shù)量,“+”開頭的字符串代表新加入的字符。所以我們可以寫一個(gè) minimizeDiffInfo 函數(shù):

  1. function minimizeDiffInfo(originalInfo){ 
  2.  
  3.     var result = originalInfo.map(info => { 
  4.  
  5.         if(info.added){ 
  6.  
  7.             return '+' + info.value; 
  8.  
  9.         } 
  10.  
  11.         if(info.removed){ 
  12.  
  13.             return '-' + info.count
  14.  
  15.         } 
  16.  
  17.         return info.count
  18.  
  19.     }); 
  20.  
  21.     return JSON.stringify(result); 
  22.  
  23.  
  24.   
  25.  
  26. var diffInfo = [ 
  27.  
  28.     { count: 3, value: 'aaa' }, 
  29.  
  30.     { count: 3, added: undefined, removed: true, value: 'bbb' }, 
  31.  
  32.     { count: 3, added: true, removed: undefined, value: 'ggg' }, 
  33.  
  34.     { count: 3, value: 'ccc' } 
  35.  
  36. ]; 
  37.  
  38. minimizeDiffInfo(diffInfo); 
  39.  
  40. //=> '[3, "-3", "+ggg", 3]'  

用戶端接受到精簡之后的 diff 信息,生成***的資源:

  1. mergeDiff('aaabbbccc''[3, "-3", "+ggg", 3]'); 
  2.  
  3. //=> 'aaagggccc' 
  4.  
  5.   
  6.  
  7. function mergeDiff(oldString, diffInfo){ 
  8.  
  9.     var newString = ''
  10.  
  11.     var diffInfo = JSON.parse(diffInfo); 
  12.  
  13.     var p = 0; 
  14.  
  15.     for(var i = 0; i < diffInfo.length; i++){ 
  16.  
  17.         var info = diffInfo[i]; 
  18.  
  19.         if(typeof(info) == 'number'){ 
  20.  
  21.             newString += oldString.slice(p, p + info); 
  22.  
  23.             p += info; 
  24.  
  25.             continue
  26.  
  27.         } 
  28.  
  29.         if(typeof(info) == 'string'){ 
  30.  
  31.             if(info[0] === '+'){ 
  32.  
  33.                 var addedString = info.slice(1, info.length); 
  34.  
  35.                 newString += addedString; 
  36.  
  37.             } 
  38.  
  39.             if(info[0] === '-'){ 
  40.  
  41.                 var removedCount = parseInt(info.slice(1, info.length)); 
  42.  
  43.                 p += removedCount; 
  44.  
  45.             } 
  46.  
  47.         } 
  48.  
  49.     } 
  50.  
  51.     return newString; 
  52.  
  53.  

實(shí)際效果

有興趣的話可以直接運(yùn)行這個(gè):

GitHub – starkwang/Incremental

使用 create-react-app 這個(gè)小工具快速生成了一個(gè) React 項(xiàng)目,隨便改了兩行代碼,然后對比了一下build之后的新舊兩個(gè)版本:

  1. var JsDiff = require('diff'); 
  2.  
  3. var fs = require('fs'); 
  4.  
  5.   
  6.  
  7. var newFile = fs.readFileSync('a.js''utf-8'); 
  8.  
  9. var oldFile = fs.readFileSync('b.js''utf-8'); 
  10.  
  11. console.log('New File Length: ', newFile.length); 
  12.  
  13. console.log('Old File Length: ', oldFile.length); 
  14.  
  15.   
  16.  
  17. var diffInfo  
  18.  
  19. = getDiffInfo(JsDiff.diffChars(oldFile, newFile)); 
  20.  
  21. console.log('diffInfo Length: ', diffInfo.length); 
  22.  
  23. console.log(diffInfo); 
  24.  
  25.   
  26.  
  27. var result = mergeDiff(oldFile, diffInfo); 
  28.  
  29. console.log(result === newFile);  

下面是結(jié)果:

 

可以看到 build 之后的代碼有 21w 多個(gè)字符(212KB),而 diff 信息卻相當(dāng)短小,只有151個(gè)字符,相比于重新加載新版本,縮小了1000多倍(當(dāng)然我這里只改了兩三行代碼,小是自然的)。

一些沒涉及到的問題

上面只是把核心的思路實(shí)現(xiàn)了一遍,實(shí)際工程中還有更多要考慮的東西:

1、服務(wù)器不可能對每一次請求都重新計(jì)算一次 diff,所以必然要對 diff 信息做緩存;

2、用戶端持久化儲(chǔ)存的實(shí)現(xiàn)方案,比如喜聞樂見的 LocalStorage、Indexed DB、Web SQL,或者使用 native app 提供的接口;

3、容錯(cuò)、用戶端和服務(wù)器端的一致性校對、強(qiáng)制刷新的實(shí)現(xiàn)。 

責(zé)任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2022-06-23 07:05:46

跳板機(jī)服務(wù)器PAM

2016-10-26 09:12:58

2024-05-09 08:20:29

AC架構(gòu)數(shù)據(jù)庫冗余存儲(chǔ)

2018-07-10 15:30:42

Go前端更新

2018-04-18 07:34:58

2023-09-17 23:16:46

緩存數(shù)據(jù)庫

2021-10-08 23:07:02

工具AST編譯

2020-11-27 14:45:57

開發(fā)服務(wù)器代碼

2017-05-02 14:41:00

網(wǎng)絡(luò)釣魚機(jī)器學(xué)習(xí)社會(huì)工程

2024-04-30 08:12:05

CRUD方法JavaAC架構(gòu)

2024-04-26 08:58:54

if-else代碼JavaSpring

2019-11-22 09:21:17

技術(shù)研發(fā)數(shù)據(jù)

2016-10-13 10:57:55

phptcp專欄

2021-05-18 06:22:39

CSS 制作波浪技巧

2020-09-16 14:01:10

Vue.js項(xiàng)目語言

2023-01-26 23:46:15

2013-05-22 15:31:07

AOP的CGlib實(shí)現(xiàn)

2009-06-03 15:38:37

Struts框架RBAC

2010-08-23 14:25:13

marginCSS

2022-08-01 12:53:30

前端動(dòng)畫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號