有幸作为讲师受邀参加InfoQ在上海举办的QCon2017,不得不说,不论是从讲师还是听众的角度衡量,QCon进一步扩大了技术视野。虽然前端专题只有四场,但每一场分享都是目前的热门话题。并且Qcon的选题都是从实践出发,并没有一些看起来很炫但是尚未经过实践检验的新技术,即使是目前刚刚起步且相对来说比较小众的WebAssembly也是以饿了么的生产实践为基础。

我的分享话题是《面向SPA和Hybrid应用的前端工程体系和实践经验》,从我个人角度来讲还是缺乏演讲技巧,语速过快导致比预期的时间提前了将近1/3,为听众正确到了一个比较长的茶歇时间╮(╯▽╰)╭。演讲结束后与支付宝的同行探讨了一些相关的问题,挖掘了目前搜狗地图团队从工程角度的一些不足和启发,比如模板更新率以及解析速度提升等。但是与支付宝业务不同的是,搜狗地图中对于模板的定义并不是“离线包”,而是一种类似于html模板的动态解析“引擎”。

分享的现场在正式进入话题前与现场的听众进行了一次小小的互动:粗略统计了一下当时在场的人当中搜狗地图的用户比例。尴尬的是,除了出品人@winter老师碍于面子举起了手以外,现场并没有第三个搜狗地图用户(我是第二个╮(╯▽╰)╭)。当然,这也算是意料之中,搜狗地图虽然国内的市场占有率并不高,甚至我在QCon讲师微信群里打招呼后有位老师竟然问“搜狗开始做地图了?”。“开始”这个词用的真是很尴尬啊,那么我就先科普一下搜狗地图的历史吧。

搜狗地图前身是图行天下,成立于1999年,是国内第一家互联网地图服务网站,2005年被搜狐收购后改名为“搜狗地图”。所以这个刚“开始”做的地图产品比大多数人预料的还要老。讲历史主要不是为了科普,也不是倚老卖老,而是从侧面阐明我们在进行工程化改造时所面临的项目特征:一个有着近20年历史包袱、模块结构混乱的“老家伙”(PS:搜狗地图目前的pc web地图可以完美兼容IE5╮(╯▽╰)╭)。这样的老项目不可能短时间内切换到全新的技术栈,也不可能大胆地使用一些比较潮的技术和框架,更多的是从策略的角度进行优化。所以我分享内容更加贴近于经验而不是技术本身,相比较其他三位的话题,我所分享内容的方方面面几乎是每个人都熟悉的,我们的工作便是综合这些成熟且稳定的“常识技术”进行工程优化。

前端工程体系并不是一个固有名词,每个团队由于组织、业务以及架构上的不同,对于前端工程体系的理解的也不尽相同。在进入正题之前必须区分的两个概念是:工程化与工程体系。工程化是一个动词,意指将业务项目进行工程改造,比如合理的模块化、前后分离等等;而工程体系是一个名词,可以理解为工程化的外在表现以及辅助框架,比如构建、测试、部署等等。搜狗地图前端团队对前端工程体系的理解是:工程体系本质上是一种服务,其服务的对象是技术团队所采用的技术以及组织架构。而架构本身也定位为一种服务,其服务的对象是具体的业务。所以在这一层三角关系之中,业务是决定所有服务的核心和出发点。我们经常将的一句话是:技术不能脱离业务。我也希望这句话能够成为每一个技术开发者和决策者的座右铭。

从业务出发进行工程优化的第一步是提炼业务特征,从而选择合理的技术和组织架构。我们从四个方面提取业务特征:场景、类型、设备以及平台。

以Web地图业务为例,从进入页面到展示完整地图的工作流程大致如下:

地图可以说是将按需加载发挥到极致的最佳实践业务。大家可以想象一下,以街道为维度将北京市的全貌绘制到浏览器中,浏览器能否承载如此大的工作量?即使抛开技术的局限性,单纯从需求的角度来讲,用户通常只需要查看以当前位置或者搜索位置为中心的有限区域内的地图。所以对于地图来说,第一步也是最重要便是定位

  1. 进入页面后首先请求定位服务,此时页面的状态是loading,也有人将其称为骨架页面;
  2. 定位成功后,用户所在位置的经纬度以及对应比例尺数据决定后续瓦片数据的获取;
  3. 瓦片数据请求成功后,浏览器端JS代码将其排列组合最终展示出完整的局部地图。

精确定位是非常复杂的功能,感兴趣的可以自行查阅相关资料。

除了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的入口、由服务端数据驱动的Content;
  • pageA打开pageB的方式是新建一个Webview;
  • pageB中的表单提交数据到服务端,成功后返回pageA;
  • pageA需要获取经pageB修改后的服务端数据,最简单粗暴也是最省事的办法就是:刷新。

这种方案存在的致命缺陷在于,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下载

上海2017QCon个人分享总结的更多相关文章

  1. 上海苹果维修点分享苹果电脑MACBOOK故障维修常见案例

    苹果的电子设备无论是外观和性能都是无与伦比的美丽,很多开发者都开始选用苹果电脑macbook.近年来苹果售后维修点来维修苹果电脑的用户也越来越多,我们上海苹果维修点就整理分享了一些苹果电脑MACBOO ...

  2. 开拓新途径找出新方法,上海SEO公司分享3个操作看看是否可行

    开拓新途径找出新方法,上海SEO公司分享3个操作看看是否可行 内容收录,外链公布,流量点击.用户体验.这是SEO优化的几个核心和重点.也是SEO站长每天都在绞尽脑汁进行操作的SEO重心,影响着非常多人 ...

  3. K2上海总部技术培训分享笔记

    第一部门 WinDdg 入门指南 1.NGen.exe --> native code 预编译,省去了.NET程序编译器JIT过程,是程序第一次运行也非常快. NGen 参考资料:http:// ...

  4. 阿里内部分享:我们是如何?深度定制高性能MySQL的

    阿里云资深数据库工程师赵建伟在“云栖大会上海峰会”的分享.核心是阿里云的数据库服务和MySQL分支的深度定制实践分享. 阿里巴巴MySQL在全球都是有名的.不仅是因为其性能,还因为其是全世界少数拥有M ...

  5. 微信小程序框架探究和解析

    何为框架 你对微信小程序的技术框架了解多少? 对wepy 框架进行一系列的深入了解 微信小程序框架解析和探究 小程序组件化框架WePY 在性能调优上做出的探究 开发者培训班上海专场PPT分享:小程序框 ...

  6. Go将统治下一个10年?Go语言发展现状分析

    “本文是国内Go语言大中华区首席布道师——许式伟,在QCon2015上海站上的分享.他预测Go语言10年内一定会超过C和java,并且统治这一个10年. Go语言语法及标准库变化 Go从1.0版本到现 ...

  7. 2018年1月20日上海MVP线下技术分享会纪实

    1月20日正值大寒节气,在微软MVP朱兴亮的组织牵头下,上海MVP自发举办了题为<跟社区专家一起聊聊混合云.领域驱动.区块链和数字营销>的技术交流会.四名来自上海的MVP分别在自己擅长的技 ...

  8. 分享 KubeCon 2019 (上海)关于 Serverless 及 Knative 相关演讲会议

    有幸参加了 KubeCon 2019 上海大会,并参加了 Knative 及 Serverless 相关的几场分享会,收获满满.这里简单介绍一下各个演讲主题的主要内容.详细的演讲主题文档可以在Kube ...

  9. 2017上海QCon之旅总结(上)

    本来这个公众号的交流消息中间件相关的技术的.这周去上海参加了QCon,第一次参加这样的技术会议,感受挺多的,所以整理一下自己的一些想法接公众号和大家交流一下. 下面进入正题,从自己参加了的一些分享中挑 ...

随机推荐

  1. JAVA课程设计 计算器模拟程序 王华俊(201521123015)

    1.团队课程设计博客链接 http://www.cnblogs.com/yuanj/p/7072137.html 2.个人负责模块或任务说明 GUI界面设计 各类之间拼接 3.自己的代码提交记录截图 ...

  2. java从控制台接收一个数字

    //时间:2017/7/22//作者:江骆//功能:从控制台接收一个数import java.io.*;  //引入一个IO流的包public class helloworld1{    public ...

  3. windows 2008 R2操作系统上使用iis服务运行php和mysql数据库的网站遇到的验证码不显示问题?

    1,本地运行正常,路径没问题. 2,GD2.dll开启 3,IIS服务正常开启,并启用父路径为True 4,检查是否IIS服务中FSO权限问题 开始 -> 程序 -> 管理工具 -> ...

  4. Apache Spark 2.2.0 中文文档 - 快速入门 | ApacheCN

    快速入门 使用 Spark Shell 进行交互式分析 基础 Dataset 上的更多操作 缓存 独立的应用 快速跳转 本教程提供了如何使用 Spark 的快速入门介绍.首先通过运行 Spark 交互 ...

  5. oracle "记录被另一个用户锁定"

    出现的原因是有人对某一条数据进行了修改,oracle会通过这个事务记住这条数据,若修改的人没有进行提交或进行回滚记录,oracle是不允许对这条数据在此进行修改的,在这种情况下你要进行修改数据,则会被 ...

  6. Centos7环境下使用Nginx托管.Net Core应用程序

    一.安装.Net Core 参考官方文档:https://www.microsoft.com/net/core#linuxcentos 1.添加dotnet产品Feed 在安装.NET Core之前, ...

  7. Training little cats poj3735

    Training little cats Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9299   Accepted: 2 ...

  8. css 浮动和清除浮动

    在写页面布局的过程中,浮动是大家经常用的属性.在好多的排版布局中都是用的的浮动比如说下面这些地方都是应用到了浮动. 在我学习浮动的时候可是熬坏了脑筋,在这里我分享一下我对浮动这块知识的总结. 一.浮动 ...

  9. bzoj2730(矿场搭建)

    矿场搭建,不知道为什么,莫名其妙T了在212上,额,zyh数据真的坑. bzoj200轻松跑过啊. 就是点双联通分量缩点,然后标记割点,一个块如果有>=2个割点,则不需要挖矿洞, 如果只有一割点 ...

  10. Thirft框架快速入门

    Thrift介绍1.什么是thrift?thrift早期由facebook内部团队开发,主要用于实现跨语言间的方法调用,属于远程方法调用的一种,后开源纳入apache中,成为了apache thrif ...