网页更新的实现方案
优采云 发布时间: 2022-08-10 00:30网页更新的实现方案
前端页面热更新
了解过前端性能优化的同学应该清楚,给页面加载提速的终极方案就是CDN,这是BS架构本身的特点决定的,无论什么前端提速手段,最终都会回到客户端文件的传输上来;与之相对的CS架构则不存在加载压力,但CS架构的问题是更新不灵活,那么有没有一种方法能结合这两种架构的优点,在加载速度和更新灵活性之间找到一个平衡点呢?这就是本文要探讨的一种方案:前端热更新。
方案概述
“前端”和“热更新”这两个词通常很少一起出现,提到热更新一般都是指APP的一种静默更新方式,这种方式会在用户使用时悄悄检测并下载增量更新包,当用户下次打开APP时自动应用更新,从而将APP“更新”这个破坏连贯性的动作隐藏于无形;前端页面的加载则相当于每次都是“全量更新”,如果能让前端页面也能用上“本地模板”,那将极大缩短前端加载时间,而且以此为前提,我们也可以实现一个前端的模板热更新机制,做到不影响页面更新的实时性。
应用场景
场景一:APP内嵌页面。
比如电商类APP的首页,经常需要改版或者做活动皮肤,如何减少更新成本就成了一个大问题。使用了热更新方案我们就可以用HTML实现APP首页,页面内容以模板的形式存进localStorage,后台静默更新模板,下次启动自动生效;针对具有一定时效性的活动皮肤,我们以补丁的形式发布,补丁文件叠加在模板上产生最终的活动模板效果,对于补丁包我们可以提前加载并预存在本地,补丁包应该包含自身的生效时段信息,前端检测到时间处于活动周期内时应用补丁。最终可以做到热更新页面无论改版还是做活动,只需要前端发版就可以,完全不需要APP端参与。
场景二:追求加载速度的web页面。
对于web页面来说更新不是问题,加载才是最大的问题,如果个别页面希望极致提升页面展现速度,那么也可以使用该方案作为提速手段,但因为页面的所有代码都将存进localStorage,所以不适合大范围使用。
需求细化
综合以上场景和需求,最终我们要做的东西是一个“壳”页面,该页面没有具体业务内容,只实现热更新功能,每次加载都先检查localStorage中是否存在模板,如果有则立即应用模板,此时页面展现出来,如果没有则进入下一步;下一步页面会请求模板管理接口获取最新模板信息,拿到模板信息后如果本地已有模板,则与本地模板比对版本信息,如果版本一致说明缓存命中,流程结束;如果本地版本不是最新,则获取最新模板并存进本地,下次页面加载时将应用最新的模板,流程结束;另一种情况是首次加载本地没有任何模板,那么将获取最新模板,保存到本地,然后应用模板,流程结束。
前面说的是稳定模板的更新流程,稳定模板流程结束后会进入补丁模板更新流程。首先仍然是检查本地是否存在补丁模板,如果已存在则检测当前时间是否匹配补丁的生效时段,匹配则应用补丁,不匹配将进入下一步;下一步将获取最新补丁模板并存到本地,然后检测当前时间是否匹配最新补丁的生效时段,如果匹配则应用模板,不匹配流程结束。
完整流程如图所示:
实现细节
接口数据
根据功能需求我们需要接口返回稳定模板信息和活动模板信息,分别都包含id和url两个字段,id用于版本校验,url指向模板文件下载地址,活动模板信息还需要额外提供cycle字段,定义活动模板的生效时段,与之相对的我们还需要接口返回服务器当前时间,用于匹配活动模板的生效时段,最终完整的数据结构如下:
{ "status": "Y", "data": {<br /> "stableVersion": {<br /> "id": "17",<br /> "url": ""<br /> },<br /> "activeVersion": {<br /> "id": "18",<br /> "url": "",<br /> "cycle": "2018,02,01-2018,02,10"<br /> },<br /> "today": "2018,02,06" }<br />}
本地数据
保存到本地的数据大致跟接口数据保持一致,只保留stableVersion和activeVersion信息,字段在id和url基础上再增加template用于保存模板字符串,完整本地数据结构如下:
{ "stableVersion": {<br /> "id": "17",<br /> "url": "",<br /> "template": "" }, "activeVersion": {<br /> "id": "18",<br /> "url": "",<br /> "cycle": "2018,02,01-2018,02,10",<br /> "template": "" }<br />}
模板文件
前端页面由三种语言构成,但我们希望只用一次请求就把模板文件拿到,所以模板是一个包含了html/css/js的文本文件,标签格式就保持普通HTML文件的写法,考虑到模板应用部分的实现,需要约定一下标签的写法,例如css必须用标签包裹,js必须用标签包裹,这样一来用正则表达式就很容易提取到各部分代码段。
模板应用
如上段所说,获得模板文件后可以使用正则表达式拿到三种语言代码,然后只需要按照css > html > js的顺序依次将他们插入页面相应位置,就完成了模板应用,唯一不同的是html代码将以innerHTML的方式覆盖进body元素。在应用顺序上,将css放在html之前是为了避免重绘,将js放在html之后是为了能够在js中操作DOM。
活动模板虽然定义为补丁,但模板构成跟稳定模板其实是相同的,应用方式也完全相同,只不过由于活动模板在稳定模板之后应用,所以活动模板的css和js都将以补丁的方式影响页面,对于普通的换皮肤需求只需要css和js就足够了,但如果希望html也能发生一些改变,根据html的覆盖式应用方式,活动模板中就需要给出一份完整的html代码,以达到修改html的目的。