有幸做为讲师受邀参加InfoQ在上海举办的QCon2017,不得不说,不管是从讲师仍是听众的角度衡量,QCon进一步扩大了技术视野。虽然前端专题只有四场,但每一场分享都是目前的热门话题。而且Qcon的选题都是从实践出发,并无一些看起来很炫可是还没有通过实践检验的新技术,即便是目前刚刚起步且相对来讲比较小众的WebAssembly也是以饿了么的生产实践为基础。css
个人分享话题是《面向SPA和Hybrid应用的前端工程体系和实践经验》,从我我的角度来说仍是缺少演讲技巧,语速过快致使比预期的时间提早了将近1/3,为听众争取到了一个比较长的茶歇时间╮(╯▽╰)╭。演讲结束后与支付宝的同行探讨了一些相关的问题,挖掘了目前搜狗地图团队从工程角度的一些不足和启发,好比模板更新率以及解析速度提高等。可是与支付宝业务不一样的是,搜狗地图中对于模板的定义并非“离线包”,而是一种相似于html模板的动态解析“引擎”。html
分享的现场在正式进入话题前与现场的听众进行了一次小小的互动:粗略统计了一下当时在场的人当中搜狗地图的用户比例。尴尬的是,除了出品人@winter老师碍于面子举起了手之外,现场并无第三个搜狗地图用户(我是第二个╮(╯▽╰)╭)。固然,这也算是意料之中,搜狗地图虽然国内的市场占有率并不高,甚至我在QCon讲师微信群里打招呼后有位老师居然问“搜狗开始作地图了?”。“开始”这个词用的真是很尴尬啊,那么我就先科普一下搜狗地图的历史吧。前端
搜狗地图前身是图行天下,成立于1999年,是国内第一家互联网地图服务网站,2005年被搜狐收购后更名为“搜狗地图”。因此这个刚“开始”作的地图产品比大多数人预料的还要老。讲历史主要不是为了科普,也不是倚老卖老,而是从侧面阐明咱们在进行工程化改造时所面临的项目特征:一个有着近20年历史包袱、模块结构混乱的“老家伙”(PS:搜狗地图目前的pc web地图能够完美兼容IE5╮(╯▽╰)╭)。这样的老项目不可能短期内切换到全新的技术栈,也不可能大胆地使用一些比较潮的技术和框架,更多的是从策略的角度进行优化。因此我分享内容更加贴近于经验而不是技术自己,相比较其余三位的话题,我所分享内容的方方面面几乎是每一个人都熟悉的,咱们的工做即是综合这些成熟且稳定的“常识技术”进行工程优化。web
前端工程体系并非一个固有名词,每一个团队因为组织、业务以及架构上的不一样,对于前端工程体系的理解的也不尽相同。在进入正题以前必须区分的两个概念是:工程化与工程体系。工程化是一个动词,意指将业务项目进行工程改造,好比合理的模块化、先后分离等等;而工程体系是一个名词,能够理解为工程化的外在表现以及辅助框架,好比构建、测试、部署等等。搜狗地图前端团队对前端工程体系的理解是:工程体系本质上是一种服务,其服务的对象是技术团队所采用的技术以及组织架构。而架构自己也定位为一种服务,其服务的对象是具体的业务。因此在这一层三角关系之中,业务是决定全部服务的核心和出发点。咱们常常将的一句话是:技术不能脱离业务。我也但愿这句话可以成为每个技术开发者和决策者的座右铭。
后端
从业务出发进行工程优化的第一步是提炼业务特征,从而选择合理的技术和组织架构。咱们从四个方面提取业务特征:场景、类型、设备以及平台。
浏览器
以Web地图业务为例,从进入页面到展现完整地图的工做流程大体以下:
缓存
地图能够说是将按需加载发挥到极致的最佳实践业务。你们能够想象一下,以街道为维度将北京市的全貌绘制到浏览器中,浏览器可否承载如此大的工做量?即便抛开技术的局限性,单纯从需求的角度来说,用户一般只须要查看以当前位置或者搜索位置为中心的有限区域内的地图。因此对于地图来讲,第一步也是最重要即是定位:服务器
精肯定位是很是复杂的功能,感兴趣的能够自行查阅相关资料。微信
除了Web地图之外,搜狗地图前端业务的另外一种主要形式是Hybrid。将这两种业务形式进行概括总结,提取的业务特征大体以下:
网络
业务特征决定技术架构,最终提炼出适用于搜狗地图前端业务的架构类型即是目前较流行的单页应用—SPA。
不依赖与服务端渲染的SPA不管是从架构层面,仍是从开发和部署层面都带来不少便利。HTML文档能够做为一种静态资源与js、css等一同部署,然而从缓存处理方面,须要单独处理HTML这种“特殊”的静态资源。它的特殊之处便在于:HTML是全部其余静态资源的入口。
HTML的特殊性决定它不能使用http强制缓存策略,只适用于协商缓存:
这样能够保证各种型资源实时性的同时,最大化利用http缓存,对于常规的SPA项目(好比Web地图)是一种比较普适的方案。然而协商缓存必需要求一次真实有效的http请求以便服务器进行缓存有效性断定,离线场景下并不适用。而离线是Hybrid应用较广泛的场景之一,后续会提到如何在协商缓存理念基础上的优化策略。
搜狗地图Hybrid架构经历了三个阶段,最初始的方案是:Web多页项目+多Webview。也就是说,每一个Webview承载一个Web页面,页面之间的切换就是Webview之间的切换,页面之间的通讯即是Webview间的通讯。
这种架构一个最大的问题是:各页面之间的通讯很是不畅,并且影响用户体验。以下所示的是一个很是广泛的场景:
这种方案存在的致命缺陷在于,pageA并不知道pageB是否提交了表单[注],因此返回pageA后不论pageB操做与否都要进行刷新。不管是从节省流量仍是用户体验的角度来说都是负面的。
注:pageA其实有办法获取pageB是否进行了提交。一种方案是经过localstorage的storage事件,然而兼容性很是不理想;另外一种方案是经过native提供特定的接口,这种方案虽然兼容性好可是须要客户端的开发工做。
在上述问题的基础上进行优化的第一步,是结合SPA架构和Webview自身的缓存机制。
Webview的缓存机制包括如下几种:
LOAD_CACHE_ONLY
- 不使用网络,只读取本地缓存数据LOAD_DEFAULT
- 根据cache-control决定是否从网络上取数据LOAD_NO_CACHE
- 不使用缓存,只从网络获取数据LOAD_CACHE_ELSE_NETWORK
- 只要本地有,不管是否过时,或者no-cache,都使用缓存中的数据其中LOAD_DEFAULT
是最接近常规浏览器的缓存机制,在这种模式下,结合上文提到的SPA缓存策略,与常规的Web页面并没有二致。然而App并非常规的浏览器,其使用场景(手机)的特殊性要求咱们在一些特殊的方面进行优化,好比缓存清理和离线使用。
其中第一条是历史缘由,公司运维层面将CDN缓存有效期固定位1小时,迁移优化成本较高。http缓存过时后并不会自动清理,之因此常规浏览器不用顾忌这个问题是因为PC设备储存空间大,而且可使用电脑管家之类的优化软件手动清理。虽然手机等移动设备的储存空间也不断加大,但仍然有至关一部分设备的储存空间十分感人(我本身用的16G的iphone 7P,感同身受╮(╯▽╰)╭)。若是听任过时的http缓存无论便会形成app占用的空间愈来愈大,极端的用户可能一气之下就把app卸载了,我本身便曾经在阴阳师和狂野飙车之间作过抉择,最终卸载了阴阳师╮(╯▽╰)╭。
因此这并非最终合理的方案,可是此次探索给了进一步的优化工做灵感:是否是能够吸收协商缓存的理念,同时结合Webview自身的缓存机制呢?以此为方向便产生了目前采用的协商缓存理念的Hybrid模板更新策略。
模板是什么?前文提到了模板并非静态的离线包,而是具有动态数据解析功能的逻辑模块。这个理念来源于SSR(服务端渲染)中的html模板,这应该是前端工程师们再熟悉不过的名词了,前几年还没有实现先后端分离开发时,html模板能够说是折磨前端工程师的主力之一。
模板以压缩包的形式传输,进入App以后若是处于Wifi环境则会自动检查并下载最新版本的模板包。而且在App进程运行以及挂起期间不会进行屡次检查。
具体每一个模板包对应的页面,进入以后并不会检查模板包的版本,只要本地存在便展现,不然fallback展现线上的Web URL。这种策略是为了尽量减小具体业务页面的解析时间。做为fallback的Web地址采用WebView的LOAD_DEFAULT
缓存策略,有效期为CDN缓存(1小时)。另外,若是用户经过任务管理器手动杀死了App进程,下次进入App以后首先会清理以前残留的http缓存文件。
综上,搜狗地图的前端工程体系简易架构大体以下:
与常规Web项目的不一样点在于,地图项目大量使用SVG和Canvas,组件库包括二者相关的组件。另外,负责与native通讯的bridageJS是Hybrid应用所特有的。平台层由Gitlab把关,Webhook触发自动构建、测试和部署。另外,模板包能够由开发人员直接部署,不须要通过公司运维,这也是与常规Web项目相比的优点之一。
因为每一个模板包都会对应一个fallback的Web地址,因此在构建流程中须要针对两种场景分别构建。模板文件对于App来讲其实就是本地文件,因此模板文件中对于其余文件的引用统一使用相对地址,而且因为模板自己就是增量的,无需在静态文件名中加入hash指纹。构建工具备Node.js为底层平台,使用特殊的环境变量结合EJS引擎区分构建,以下:
至此即是搜狗地图目前针对SPA和Hybrid项目的总体工程体系,固然这并非终点,甚至称不上是最佳实践。这次分享的目标也并非剖析咱们团队的工程实践,更多的是将这一路走来的探索历程分享给你们,但愿可以给一样面临老项目改造的团队一些启发。
最后简单提一个优化的案例。模板也是分模块的,不能将全部的业务集中在一个模板中,不然任何一个微小的修改都会形成整个模板包的更新,并且随着业务的不断扩展,模板包的体积愈来愈大,下载和解析时间最终会超过用户的心理承受界限。因此咱们在模板颗粒度划分方面作了一些优化:将逻辑无耦合的业务定义为一个模板包,好比用户中心与详情页,二者除了登陆信息共享之外,几乎不存在逻辑上的耦合,因此将二者划分为两个模板。在此基础上将共用的类库文件提取出来单独做为一个模板。
若是让我给这套工程体系打分可能只达到了60分的及格线,可是对于一个“历史悠久”的团队而言,这仍然是很是可观的“一大步”。后续仍然须要不断进行优化和迭代,好比会后与支付宝的同窗一块儿探讨的更新率问题。技术的道路远没有尽头,回到一开始的那句话:技术永远服务于业务。总结此次的QCon之行,我看到了优秀的技术从业者们以实际业务为中心的探索和务实精神,收获的不只仅是技术的增加,更重要的是扩宽了眼界。
最后,感谢主办方InfoQ的邀请,完整PPT下载。