没有合适的轮子,只好自己造( ╯□╰ )
模块化
模块化在当前大中型web项目开发中已经成为共识,从浏览器端AMD的requirejs到node.js遵循的commonjs规范,再到ES6开放了import关键字来管理模块都是最好的说明。其优势就是方便多人协作开发,代码可移植性可测试性高。
angular本身自带模块定义和依赖管理功能,这个模块管理一般是怎么使用的?
我们找个网站分析一波~
作为爱智求真的小伙伴,我们就来看看 知乎 旗下的 知乎专栏 。
先打开调试工具,截个图慢慢看~
点开这个带有hash戳被压缩的js文件,可以看到如下几个模块:
|
|
这里声明了3个模块:
auth
模块依赖了auth.interceptor
模块。auth.interceptor
模块无依赖。columnWebApp
模块是个花心大萝卜,和一堆的模块有依赖关系。
弱弱地吐槽一波:用匿名函数做闭包来避免全局污染的是常见的传统做法,这里初步判断应该是由多个js文件合并而成,这里起码有两点是可以改进的。 一是window
、angular
这种全局变量完全可以传参到闭包内部便于代码压缩,例如:
|
|
二是这种压缩打包的方式还是比较粗糙的,建议开发人员有时间还是可以将多余的模块引用去掉,变成链式调用,例如:
|
|
另外严格模式也建议开启。
吐槽 end~
从上面的例子可以看出,Angular项目通用的做法是:开发的时候按照业务逻辑写成不同的js文件,然后把这些js文件压缩合并成一个或多个,在用户第一次访问的时候全部返回给浏览器做预加载。
这种处理方式在小型网站还好,性能要求不高的中型网站也勉强可用,但是对于对于大型网站影响,随着js文件变多用户首次访问的加载时间会跟着增加,看看那些PV上千万、上亿的网站为了首页优化各种技术层出不穷。而且这种处理方式也是很不合理的,用户可能只想看看首页或者只使用某个功能模块,为毛要把所有的代码都家再过来浪费用户时间?
张鑫旭写过一篇 《基于用户行为的图片等资源预加载》 说的也是类似问题。这个解决思路很有意思,分析用户的操作行为,按需进行预加载。有兴趣大家可以看一看。
既然有了这个需求,我们看看目前有什么现成的解决方案~
按需加载
目前angular项目普遍使用ui.router模块已经成了不争的事实了,用它来管理每个“页面(视图)”和“页面对应的业务逻辑(控制器)”,依照大多数人的直觉思维。将按需加载理解为按页面加载,于是便出现了一些解决方案,基本思路都是一致的:
在“页面(视图)跳转”的时候,按需加载业务逻辑(控制器)。而恰好ui.router模块在配置路由的时候提供了一个resovle属性,可以在页面逻辑(控制器)加载之前进行一些操作。略有不同的便是有的使用了oclazyload,这个还比较好,起码是遵循angular框架的第三方模块,有的使用了requirejs,这种感觉就像是阿玛尼西装配阿迪达斯球鞋,虽然都是“阿”字系的,但想去甚远,做angular开发的时候还是尽量不要应用不按照angular规范开发的第三方插件,毕竟angular这种强框架不像requirejs有shim,所以还是避免给自己挖坑。
可这真的就是完美的解决方案吗?起码有以下几个问题:
- 每次“页面跳转”都要额外请求js并加载,浪费带宽增加页面加载时间,基本抛弃了预加载。
- 每一个路由都需要配置resolve属性,太low。
- 模块化程度太低,不利于以后代码移植和维护。
模块按需加载
将前面提到的模块化和按需加载结合起来看,比较好的解决方案应该是:按照业务功能划分模块,当用户点击某个功能模块的时候,按需加载该功能所需的文件。
举个不太恰当但容易理解的例子,当用户点击百度音乐的时候,从用户行为角度分析,这个用户很有可能会进行一些相关操作:比如搜歌、听歌等等。同时很有可能用户当前并不会访问贴吧或者新闻。所以此时按需加载音乐模块的代码逻辑,对于后续的搜歌、听歌操作实现了预加载。
这样的实现方式还会带来其它好处,下回详述~
同时也欢迎读者提供好的想法或者其它解决方案~ (●’◡’●)
一部由众多技术专家推荐, 帮你成为具有全面能力和全局视野工程师的进阶利器—— 《了不起的JavaScript工程师》出版了! 点击下方链接即刻踏上进阶之路!
- 淘宝:https://detail.tmall.com/item.htm?id=600756390664
- 京东:https://item.jd.com/12562349.html?dist=jd
- 当当:http://product.dangdang.com/27922044.html