requireJS
CommonJS规范不适用于浏览器环境,这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。
因此,浏览器端的模块,不能采用”同步加载”(synchronous),只能采用”异步加载”(asynchronous)。这就是AMD规范诞生的背景。AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:require([module], callback);第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。
使用requireJS的优点有哪些?
- 实现JS文件的异步加载,避免网页被堵塞。
- 管理模块之间的依赖性,便于代码的编写和维护。
require.js要求,每个模块是一个单独的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了一个优化工具,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。
引入步骤:
- 在页面头部head标签内引入requireJS,如下:<script src=”js/require.js”></script>,但是加载这个文件也会造成网页失去响应,我们可以加上defer和async这个属性。如下:<script src=”js/require.js” defer async=”true” ></script>,Async属性表明文件需要异步加载,IE不支持这个属性,只支持defer,所以上面把这2个属性都加上。
- requireJS启动加载脚本的初始化方式,requireJS支持属性data-main这个属性来加载初始化的JS文件,如下:>script src=”js/require.js” defer async=”true” data-main=”js/main.js”></script< 上面的意思是:先异步加载requireJS文件,完成后继续异步加载app.js文件。上面的app.js后的.js可以去掉,因为requireJS源码已经默认都是以后缀JS文件结尾的。
- data-main属性所指的js我把它称为”主模块”,意思是整个网页的入口代码。它有点像C语言的main()函数,所有代码都从这儿开始运行。
模块步骤:
- RequireJS编写模块不同于其他脚本文件,它良好的使用define来定义一个作用域避免全局空间污染,它可以显示出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入。
- define中直接返回一个对象,可以解决全局变量的理念。比如全局变量全部使用define函数包围,什么时候需要全局变量的话,直接require([‘XX’],function(XX){})这样调用下。
- 使用require.config()方法,我们可以对模块的加载行为进行自定义。require.config()就写在主模块(main.js)的头部。
- If a module ID has one of the following characterstics, the ID will not be passed through the “baseUrl + paths” configuration, and just be treated like a regular URL that is relative to the document:
Ends in “.js”. Starts with a “/“.
*Contains an URL protocol, like “http:” or “https:”。
AMD模块定义1
2
3
4
5
6
7
8
9
10 //包装模块 使用exports或者module.exports导出API
define(function(require, exports, module) {
//require require函数
//exports exports空对象 被注入对象
//module module模块对象 含有id、uri等 ***id:"app/faq" ***uri:"js/app/faq.js"
var base = require('base'); //可拿到了
exports.show = function() {
//todo with module base
}
});
requireJS配置项
- baseUrl:指定本地模块的基准目录,即本地模块的路径是相对于那个目录的。该属性通常有requireJS加载时的data-main属性指定。如果未显示设置baseUrl,则默认值是加载require.js的html所处的位置,如果使用了data-main属性的话,则该路径变成了baseUrl。
- paths:paths是映射那些不直接放在baseUrl指定的目录下的文件,设置paths的起始位置是相对于baseUrl的,除非该paths设置是以”/”开头或含有URL协议(http://或者https://).
1
2
3
4
5
6
7
8
9
10// 关键点是确定目录 默认是在lib下加载 当是app时就是app下
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
}
});
requirejs(['app/a'],function(a){
});
shim参数
- 解决了使用非AMD方式定义的模块(如jquery插件)及其载入顺序,为那些没有使用define()来声明依赖关系,设置模块的”浏览器全局变量注入”型脚本做依赖和导出配置。
- 也就是说shim这个参数可以解决没有使用define(function(){})这样的文件包围的代码或者一些全局变量注入,可以确保此文件先加载,然后再加载其他文件。
shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。
1
2
3
4
5
6
7//jQuery的插件可以这样定义
shim: {
'jquery.scroll': {
deps: ['jquery'],
exports: 'jQuery.fn.scroll'
}
}如果我不使用shim这个参数的话,在最新版的requirejs2.1.15中(以前的版本我不太清楚),也可以通过require([‘XX’])来解决,如下演示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17global.js代码如下:
names = 1111;
创造一个全局变量names,其中js/app/depBase.js代码如下:
define(function(){
return {
'name':names
}
})
也就是说我在app.js代码如下初始化如下:
require.config({
baseUrl: 'js/app'
});
require(['global','depBase'],function(global,base){
console.log(base);
});
我先global初始化引入全局变量names,接着打印出depBase的返回值。也可以看到,可以引入到全局变量names的值。
Map参数
- Map参数是用来解决同一个模块不同版本的问题。比如在项目开发中,开发初期使用了jquery1.7版本,但是由于业务的需求需要引入jquery1.9以上的版本时候,但是又担心有些是依赖于jquery1.7的代码升级到1.9以上的时候会有问题,因此可以让一部分代码还是依赖于jquery1.7,新增的代码依赖于jquery1.9。
config参数
config是指需要将配置信息传给一个模块,这些配置往往是application级别的信息,需要一个手段将他们向下传递给模块。在requireJS中,基于requirejs.config()的config配置项来实现。要获取这些信息的模块可以加载特殊的依赖”moudle”,并调用module.config().
1
2
3
4
5
6//加载特殊的依赖"moudle"
define(['module'], function (module) {
//Will be the value 'blue'
var color = module.config().color;
return color;
});requireJS函数增加了第三个参数errbacks。
1
2
3
4
5require(['b'], function ($) {
//Do something with $ here
}, function (err) {
alert(err);
});在模块载入失败回调中可以使用undef函数移除模块的注册。
1
2
3
4
5
6
7
8require(['b'], function ($) {
//Do something with $ here
}, function (err) {
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'b') {
requirejs.undef(failedId);
}
});
require.js插件
require.js还提供一系列插件,实现一些特定的功能。domready插件,可以让回调函数在页面DOM结构加载完成后再运行。text和image插件,则是允许require.js加载文本和图片文件。
requireJS对文件合并与压缩:
- node r.js –o baseUrl=js name=app out=build.js
- node r.js –o baseUrl=js name=app out=build.js optimize=none
下面我们对命令分别来做一下解释:
-o: 表示优化,该参数是固定的,必选。
baseUrl:指存模块的根目录,可选。
name: 模块的入口文件,这里是app,那么r.js会从baseUrl+name去查找app.js,然后找出所有依赖的模块,然后进行合并与压缩。
out: 指合并压缩后输出的文件路径,这里是直接输出在根目录下build.js 我们也可以输出到其他目录下 比如js/app 目录下,也可以的。
optimize=none:只合并不压缩。