为啥研究or使用RequireJS?
- 异步“加载”。我们知道,通常网站都会把script脚本的放在html的最后,这样就可以避免浏览器执行js带来的页面阻塞。使用RequireJS,会在相关的js加载后执行回调函数,这个过程是异步的,所以它不会阻塞页面。
- 按需加载。通过RequireJS,你可以在需要加载js逻辑的时候再加载对应 的js模块,这样避免了在初始化网页的时候发生大量的请求和数据传输,或许对于一些人来说,某些模块可能他根本就不需要,那就显得没有必要。
- 更加方便的模块依赖管理。相信你曾经一定遇到过因为script标签顺序问题而导致依赖关系发生错误,这个函数未定义,那个变量undefine之类的。通过RequireJS的机制,你能确保在所有的依赖模块都加载以后再执行相关的文件,所以可以起到依赖管理的作用。
- 更加高效的版本管理。想一想,如果你还是用的script脚本引入的方式来引入一个jQuery2.x的文件,然后你有100个页面都是这么引用的,那当你想换成jQuery3.x,那你就不得不去改这100个页面。但是如果你的requireJS有在config中做jQuery的path映射,那你只需要改一处地方即可。
- 当然还有一些诸如cdn加载不到js文件,可以请求本地文件等其它的优点,这里就不一一列举了。
RequireJS 使用
<script data-main="js" src="xxx/xxxx/require.js"></script>
使用RequireJS,你只需要引入一个require.js即可。需要说明的是,一个比较好的实践,就是你的页面上面应该也只需要通过<script>
标签引入这一个js即可。然后你这个页面的所有业务逻辑只需要在main.js里面写(data-main
属性作用后面会有讲)就可以了。其它引用的依赖怎么办?当然是通过require按需引入啊!
其实Requirejs整个源文件包括注释就2000来行,其对外暴露的变量其实就三个,requirejs
,require
,define
。
这其中requirejs 只是require的一个别名,目的是如果页面中有require其它实现了,你还是能通过使用requirejs来使用requireJS API的(本文中没有相关冲突,所以还是使用require)。
所以这意味着作为入门,你只需要掌握require
,require.config
,define
这三样就可以了。
本文将以介绍require
,require.config
,data-main
,define
的顺序来介绍RequireJS。让比较简单的RequireJS更加简单,争取让大家只看这篇文章就能用好RequireJS。至于RequireJS是如何解决循环依赖,对于没有实现amd的模块如何通过shim来导出,如何在node中使用等问题。本文并没有提及,详细有需要可以去官方查阅。
这里拿官网的单页面作为例子,可以到这里下载create-template
目录结构只需要看www下面的就可以了,tools是打包压缩,这块可以略过。
www/ - the web assets for the project
index.html - the entry point into the app.
app.js - the top-level config script used by index.html
app/ - the directory to store project-specific scripts.
lib/ - the directory to hold third party scripts.
index.html中是这样引入requirejs的
<script data-main="app" src="lib/require.js"></script>
app其实就是app.js,在这里可以把后缀省略掉,如果看着不爽也可以加上……这样第一步就算成果了,引入requirejs。注意到标签中有一个data-main属性,你现在只需要了解require.js会在加载完成以后通过回调方法去加载这个data-main里面的js文件,所以这个js文件被加载的时候,RequireJS已经加载执行完毕。
再看看app.js是怎么写的
requirejs.config({
baseUrl: 'lib',
paths: {
app: '../app'
}
});
这里config是配置项,其中baseUrl的路径为根路径,path配置了一个模块ID和路径的映射,这样在后续的所有函数中就可以直接通过模块ID来引入依赖,而不用再多次引入依赖多次输入路径带来的麻烦。可能说的不是太明白,好,改一改例子!我在lib里面扔进去jquery.js
requirejs.config({
baseUrl: 'lib',
paths: {
app: '../app',
'jquery':['http://libs.baidu.com/jquery/2.0.3/jquery','jquery']
}
});
这里,先采用百度的cdn库来加载jquery,如果加载不到了,再使用本地的jquery,注意,jquery的路径,是在lib里面,因为设置了baseUrl为lib为根路径,所以这里如果写成lib/jquery,就错了,加载的时候就地址就变成了lib/lib/jquery.js。
再说下相对路径规则:
1.如果<script>
标签引入require.js时没有指定data-main
属性,则以引入该js的html文件所在的路径为根路径。
2.如果有指定data-main
属性,也就是有指定入口文件,则以入口文件所在的路径为根路径。
3.如果再require.config()中有配置baseUrl,则以baseUrl的路径为根路径。
以上三条优先级逐级提升,如果有重叠,后面的根路径覆盖前面的根路径。
拿第二点说,如果我config里面,没有设置baseUrl,那默认的就是www的根目录。
requirejs.config({
paths: {
app: 'app',
'jquery':['http://libs.baidu.com/jquery/2.0.3/jquery','lib/jquery']
}
});
路径这块说的有点太啰嗦了,不再说路径的问题了,其实这里也不是啥大问题,错了改改就好了……
到这里,还应该说一下第三方模块,通过require加载的模块一般都需要符合AMD规范即使用define来申明模块,但是部分时候需要加载非AMD规范的js,这时候就需要用到另一个功能:shim
,这一块先留一个坑吧,我也没有想好怎么来说,以后再说!
然后接着看app.js中config下面的,只有一句requirejs(['app/main']);
好吧,这就是加载app文件夹里面的main.js!
再改一改,还是拿jquery来做例子吧,可以改成这样
require(['jquery'],function ($) {
$(function () {
$('body').html('可以用jquery了!')
});
});
中括号中的[jquery]就是config里面的jquery,上面例子中的callback函数中发现有$参数,这个就是依赖的jquery模块的输出变量,如果你依赖多个模块,可以依次写入多个参数来使用:
require(["jquery","underscore"],function($, _){
$(function(){
_.each([1,2,3],alert);
})
})
如果某个模块不输出变量值,则没有,所以尽量将输出的模块写在前面,防止位置错乱引发误解。
讲完了如何引入模块,现在讲如何定义一个模块,require
定义一个模块是通过 define = function (name, deps, callback)
完成的,第一个参数是定义模块名,第二个参数是传入定义模块所需要的依赖,第三个函数则是定义模块的主函数,主函数和require
的回调函数一样,同样是在依赖加载完以后再调用执行。
未完待续……
如果觉得此篇文章对您有帮助,希望可以请我喝雪碧!