之前校招面试的时候遇到一个很有意思的问题:“假设有一个超级超级超级大的web项目,压缩后的JS源码超过10MB(实际上怎么会有这么大的问题=.=),要求用户每次更新后重新加载JS是不可接受的,那么如何从工程角度解决这个问题呢?一开始,我立马想到了几个方案,比如:拉出基本不常更新的模块,作为长期缓存;如果你使用支持服务端渲染的框架,比如React或Vue2.0,就使用服务端渲染,然后分块逐步加载JS;如果是Hybrid开发,可以考虑使用本地资源加载,类似于“离线包”的思路(我在腾讯实习的时候天天遇到这个东西)。后来在面试官的指导下,想到了“增量更新”的方案。简单的说就是在版本更新的时候不需要重新加载资源,只需要加载一个小的diff信息,然后合并到当前版本中即可。在资源方面,类似于gitmerge的效果。1.客户端使用LocalStorage或者其他存储方案存储一份原代码+时间戳:{timeStamp:"20161026xxxxxx",data:"aaabbbccc"}2.每次加载资源时,将这个时间戳发送给服务器;3、服务端根据收到的时间戳识别客户端的版本,与最新版本做diff,返回两者的diff信息:diff("aaabbbccc","aaagggccc");//假设我们的diff信息为可以这样表示://[3,"-3","+ggg",3]4、客户端收到diff信息后,将本地资源和时间戳更新为***,实现增量更新:mergeDiff("aaabbbccc",[3,"-3","+ggg",3]);//=>"aaagggccc"实践我们再来实现一下这个方案的核心思想,简单来说,实现diff的两个功能和mergeDiff。我今天发现了一个很好的diff算法:GitHub–kpdecker/jsdiff:Ajavascripttextdifferencingimplementation。我们只需要调用它的diffChars方法来比较两个字符串之间的差异:varoldStr='aaabbbccc';varnewStr='aaagggccc';JsDiff.diffChars(oldStr,newStr);//=>//[{count:3,value:'aaa'},//{count:3,added:undefined,removed:true,value:'bbb'},//{count:3,added:true,removed:undefined,value:'ggg'},//{count:3,value:'ccc'}]上面的diff信息有点多余,我们可以自定义一个A更简洁的表示方法,加快传输速度:[3,"-3","+ggg",3]整数表示不变的字符数,以“-”开头的字符串表示去掉的字符数,以“+”开头的字符串代表新添加的字符。所以我们可以写一个minimizeDiffInfo函数:'+info.count;}returninfo.count;});returnJSON.stringify(result);}vardiffInfo=[{count:3,value:'aaa'},{count:3,added:undefined,removed:true,价值:'bbb'},{count:3,added:true,removed:undefined,value:'ggg'},{count:3,value:'ccc'}];minimizeDiffInfo(diffInfo);//=>'[3,"-3","+ggg",3]'客户端收到精简后的diff信息,生成***资源:mergeDiff('aaabbbccc','[3,"-3","+ggg",3]');//=>'aaagggccc'函数mergeDiff(oldString,diffInfo){varnewString='';vardiffInfo=JSON.parse(diffInfo);varp=0;for(vari=0;i
