为什么使用 Containjs 模块化管理工具效率高?
要说明这个首先得说明一下,Containjs 的模块加载原理。
- 第一步,首先使用异步加载(ajax)在 js 目录下的 app.js 入口模块(Containjs内部会默认加载 ('js/app.js'))
- 第二步,生产已经加载成功模块的上下文环境
- 第三步,查找该模块文件中是否有依赖其他模块,如果有则异步加载所依赖模块,加载成功后继续第二步,直到最基础模块(没有依赖其它模块的模块)
- 第四步,等待应用所依赖模块都加载完成,则默认调用 require('js/app.js') 运行入口模块
看了 Containjs 的加载流程,好像也没明白为什么效率高对吧?下面就让我慢慢道来~
其实,奥秘就在第二步生产模块上下文和 require 加载依赖模块中。
在 Containjs 中模块加载成功后,会调用模块函数的生产函数(production),其中有一段是下面这样
// 生产模块,但是未执行
modules[url] = {
........
context : function(require, exports, module){
eval( data )
}
.......
}
上面代码中的 context 就是模块执行时候的上下文环境,很明显它被包含在一个匿名函数中,其中注入了三个接口 require、exports、module,具体什么作用这边就不多解释,可以去看我上一篇博客《Containjs是什么》。
但是,只要有点经验的人就会说,不对啊这函数中调用了 eval(data) 这效率能高吗?(其中 data 就是使用异步加载过来的模块代码字符串)
首先,说一个场景,传统的模块引入都是异步生成 script 标签然后添加到文档流中去异步加载的,加载成功后浏览器会立即解释并执行。
而 Containjs 使用的是 ajax 异步加载,加载成功后传入模块生产函数进行生产,生产的时候使用 eval() 函数进行解释 data 代码。当模块全部加载完成后,会默认调用 require('js/app.js') 入口模块,后开始执行。并且执行过后,马上被缓存模块接口,之后无论调用几次都不会在执行本模块,直接返回缓存的继承。
很多人会说 eval 效率很低啊,为什么你说效率高?是这样的,以前说使用 eval 效率低的原因场景是这样,在一个常用函数中使用 eval 比如:
// 普通定义
function add(a,b){
return a + b;
}
// 使用eval
function add(a,b){
eval('return a+b');
}
在普通定义中,return a+b 语句只被解释器,解释一次。而使用 eval 中则是每一次调用都调用 eval 解释并执行 return a+b 所以效率低。
而 Containjs 模块 eval 解释执行只会一次,之后会被缓存。传统的 script 引入也是一样代码也是会被解释执行一次。只不过发生在加载成功后马上执行而已。所以你懂的