对于微信端来说,其实使用ionic是一个比较大的前端框架。
有更多比较轻量化的前端框架可以选择。
但是使用ionic有一个明显的优点就是,能够做到一端开发,三端同步上线。
这个梗说了好多遍了,但确实是这样子的,ios和安卓都能跑了,为什么在公司的微信公众号,还要再重新开发呢。
这就是我一开始研究这个解决方案的初衷。
其实在这个方向的研究目的并不是要在性能上达到一个很好的高度,而是在首页打开速度上要取得明显的时间优势。
最开始使用requestjs把所有的文件压缩打包成一个文件,这个方案在项目还很小或者说还不是很大的时候,
将多文件小文件压缩成少文件较大文件,确实较少了网络下载请求的时间同时也变相的提速了开始应用的时间。
但是当项目中加入了微信授权,这个过程会增加3秒左右的进入首页的时间。
然后当项目越做越大,被压缩后的文件越来越大,使得网络下载时间增加,
从点击链接,进入页面,开始下载文件,下载完成,进行微信授权,授权完成页面跳转回来,再加载缓存文件(可能还重新下载),最后启动项目,进入首页。
这样一个过程,像我们公司项目比较大的时候,在安卓端(以下说的时间基本上都是指在安卓手机上的时间,在ios上,只要不是网络问题,都挺快的)需要24-37秒钟。
当然这个24秒还包含了在首页加载太多的业务的关系。反正我刚接手的时候是这个时间。
一开始我的尝试优化的方案是把微信授权的文件和主体的文件分离,首先下载一个小文件,进行微信授权,授权完毕,回调回来再下载大文件。(这个过程是同事实现的。)
调整首页的业务,和产品协商有哪些业务可以从首页中移到别的页面去。
最后重构了业务逻辑代码,把跟首页无关的业务封装到独立的服务里面。(我接手的时候很多全局通用的服务都使用$rootscope实现,这里也需要提醒大家一下)
这样一套调整优化之后,同一个测试设备上,从点击链接到进去首页的时间是8-10秒。
最后甚至去掉了微信授权,先让用户进入首页,再需要用户信息的时候再进行授权,时间还是5-10秒
有了明显的优化。
但是微信3、5、8原则,不知道大家有没有听过这个原则,就是说页面打开时间在3秒5秒8秒的时候分别对应了一定的跳出率,虽然说跳出率这种东西不能完全的认为就是这个问题引起的,但不可否认的是有一定的影响因素在里面,主要是营运指标,就拿这个说事,那就不得不改了。
在经过了一阶段的重构代码,之后,并不能显著的加快启动速度。
因此我决定放弃重构,项目重做。
这次重做涉及的项目还比较多,web端,pc官网,独立活动地址,还有sdk等等项目都要考虑在内。
不止要满足现在的指标,还要满足在公司发展的道路上,web端不再是能被提到台面上的短板。
整体的前端架构设计基本上完成了,这个有需要的话,后面也会分享给大家。
首先我新建了一个ionic的tab类型的项目,放到微信中,在同一个设备上,从点击链接到进入首页的时间是3秒钟。
ionic在安卓设备的微信端真的不是很优,空白项目也要3秒钟,那我们加了这么多图片这么多请求和业务,8秒看起来也挺好了。
我是这么想的,既然小项目的启动时间会更快,那为什么不把大项目拆成若干个小项目呢?
这里我就考虑了按需加载,这个我在之前的教程中就已经有提到了,在ionic入门教程第四课-使用$controllerProvider按需加载controller
这里我说的比较简单,也只是按需加载了controller文件,只是为了作为一个技术上的演示而已。
里面还提到了requestjs技术,这里先不提。我们纯粹的来看看按需加载。
先说说简要的思路,就是在开启项目的时候,只加载首页的相关文件,然后启动项目,再切换界面的时候再去下载新的界面。
把所有的文件细分,独立压缩,减小下载的流量。
这里需要处理几个问题,或者说是技术难点,也行。。。
1、所有的文件要支持按需加载
2、文件相关性怎么实现
3、文件独立压缩
决解方案:
1、所有的文件要支持按需加载
app.controller = $controllerProvider.register; app.directive = $compileProvider.directive; app.filter = $filterProvider.register; app.factory = $provide.factory; app.service = $provide.service; app.constant = $provide.constant; app.value = $provide.value;2、文件相关性怎么实现
走配置表的形式
3、文件独立压缩
使用grunt(使用gulp好像也行,还没去研究)
注:app.controller = $controllerProvider.register这个东西我们在第四个中有提到,其他的东西都更这个差不多,都是框架自带的懒加载的决解方案。
方案和思路说的差不多了,接下来看看怎么实现吧。我这里新建了一个tab类型的ionic项目,来作为演示。
关于项目名字,大家别太在意,我新建的时候随便敲的,要说我骚气,也行。
首先我们要把新建项目里面的controllers和services文件,里面的内容分离,之前我在第三课中讲过了使用requirejs分离controller文件和server文件,这里我们不适用requirejs。
首先我们先在app.js里面定义懒加载服务。这样我们就可以全局的只用它们,而不再需要再在单文件里面引用注入服务。
请仔细看图。图中说明的很清楚了。注意在1标注的位置要把angular.module()返回的对象存起来,在2标注的位置需要使用这个对象。
然后拆分controllers文件和services文件,首先新建一个文件夹controller,里面新建一个文件AccountCtrl.js
然后在controllers中把AccountCtrl的内容复制出来
修改头部
这里也需要注意标注2这里使用的app.controller其实是使用了$controllerProvider.register,这里直接使用$controllerProvider.register也可以,但是要保证存在$controllerProvider这个服务。所以我在app.js里面定义了。
嗯这个分离的过程很简单,我故意提出来说,其实细心的朋友应该能够发现,我在拆分这些文件的时候,并没有关注过这里面实现的业务,只是把文件复制过来修改了头部。也就是说,不管你的项目之前是用什么方式开发的,要使用我提供的这个方案,修改起来也很容易,而且不容易出错。
同样的拆分其他的控制器,将controllers文件拆分成
同样的方法拆分服务,需要注意的是服务使用的不是app.controller,而是app.factory
到此完成了第一个问题,文件拆分,并让它们符合懒加载的规范。
接下来处理第二个问题,配置表。
首先我们新建一个文件config.js放在那都行。
使用$provide.constant来定义了一个静态变量,在1图中我们已经说过了需要导入这个’JS_REQUIRES‘
这里我还多做了一个优化,把业务相关联的文件按照界面写成分组,这样在代码中就不用把太多的精力放在文件关联上。
所有的关联都在这个配置表里面实现
就是把我们第四课中提到的这个文件地址写到配置里面,这样子在代码中就只需要关注这个几面关联的模块,而不是模块的所有文件。
这也算是一种简化的模块化。
上图是第四课中的写法,我们这里使用类似但不相同的写法。第四课中是使用require和$q的组合实现的,
这里我们使用的是oclazyload和$q的组合实现。
首先在路由中的定义类似。这里提供了两种方案,一种只关联少量文件的,可以写上所有的文件,第二种关联文件较多的时候,写上关联的模块名称。
上面那个地方如果是两个文件的话可以写成loadSequence('ChatsCtrl','ChatsService')。
暂不支持模块和文件混合的方式。需要的朋友可以自己修改一下loadSequence方法,判断如果写的key在模块中匹配不到就去匹配单文件。
到此本次方案基本上都实现了,在浏览器中运行查看。
首次加载的时候只加载需要的文件,切换页面再加载其他文件,表现与预期设想相同。
用这个方案在我们公司的项目中做过测试。在文件压缩之后,在同一个测试设备上,从点击链接到进入首页,首次加载时间为3-5秒,再次加载时间为1-2秒。
而且还有一个明显的好处,不管后续项目的复杂度提升多少,都不会严重的影响这个时间。
上图中还有一个需要关注的地方,就是html文件并不是按需加载的。这个可能是我接下来需要要研究的内容。
还有就是单文件压缩,配置表管理会变得非常的繁琐。可以考虑用requirejs把这些小模块按照独立的小模块做一个个单独的打包。
这些东西都是这个方案可以继续前进的方向。希望高手能跟我一起完善它们。
至于第三点独立打包,是使用了grunt的grunt-contrib-uglify插件,用法很容易的,大家百度一下就好。有不懂得话,我后续单独出一个将这个单独打包的教程。
由于篇幅问题,我这里就不详细说明了。
看到好多的博客文章的结尾都会放上两个支付的二维码,还写着博主很辛苦请博主喝杯咖啡。我也好想丢两个给大家扫一扫,但是我又觉得这钱太少了,没什么兴趣。嗯?有需要合作的可以小窗联系我。培训质询什么的,你懂的。当然找我质询其实是免费的。我在想要是回答收费,那我可以辞职回家了。哈哈
还是那句公众号暂时没人维护。项目Demo地址:http://pan.baidu.com/s/1i4Qmkz7如果你还有什么其他的问题,可以通过以下方式找到我 新浪微博:小虎Oni 微信公众号:ionic__
有其他问题的可以关注一下公众号提问(右侧双下划线):ionic__