小编最近在研究vue-cli项目结构,但是发现里面好多关于node.js的知识。node本身遵循commonJs规范,但是作为前端开发,大部分是遵循CMD和AMD规范的,今天小编就把自己这两天学习的有关 AMD规范的一些知识整理出来,供自己日后回顾,以及大家参考!、
进入正题! AMD 英文意思是 Asynchronous Module Definition ,翻译过来的意思其实就是“异步模块定义”,其实异步的概念相信大多数朋友都理解这里就不再赘述了,其实说到异步,就不得不提同步,commomJs就是同步的,这里可以简单的知道一下。那么采用异步模块有什么好处呢?其实异步加载模块的好处说白了就是提供了一个回调函数,在加载对应模块的时候不影响其他功能模块的加载,待对应模块加载完后所有的逻辑通过回调函数触发,其实这跟java里面的线程有点类似!
学习AMD规范首先你必须的了解requireJs,因为说白了AMD规范就是reuqireJs中define(定义模块)和require(使用模块)两个模式的合称,即AMD模式!
define:定义模块的关键字,用来定义模块。requireJs要求每个模块都放在一个单独的文件中。
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);
其中:
module-name: 模块标识(模块名称),可以省略,省略时当前模块的模块名即为文件名。
array-of-dependencies: 所依赖的模块,可以省略(当依赖模块不存在时即为独立模块,参数必须为数组格式,即使只依赖一个模块)。
module-factory-or-object: 模块的实现,或者一个JavaScript对象。
定义模块时按照是否指定模块名,我们可以把定义的模块分为匿名模块和实名模块(大多数都使用匿名模块)
按照是否有依赖其他模块,我们又可以把定义出来的模块分为独立模块和非独立模块,
1)实名模块(指定模块名)
a.js文件(定义模块)
define("module1",["jquery"],function(jq){
return{
name:"zhansan",
age:28,
eat:function(){
console.log(this.name+"正在吃饭!")
}
}
})
main.js(使用模块)
require(['module1'],function(m1){
m1.eat();
})
运行结果:zhangsan正在吃饭!
上面代码的意思是指定当前模块名为“module1”,当前模块依赖于一个叫做jquery的其他模块,第三个参数是一个回调函数,当此模块在别处被require引用加载完成时,会触发此回调函数,可以在里面进行一些操作!
2)匿名模块(不指定具体模块名)
有时候我们为了方便第一个参数,即模块名,完全可以省略,当第一个参数被省略时,我们又把定义出来的模块,成为匿名模块,此时如果在别处想要使用此模块的话,可以使用文件名进行引用,此时上面的代码我们可以改写成这样:
a.js文件(定义模块)
define(["jquery"],function(jq){
return{
name:"zhansan",
age:28,
eat:function(){
console.log(this.name+"正在吃饭!")
}
}
})
main.js(使用模块)
require(['a'],function(m1){
m1.eat();
})
当时这样写的前提是你的a.js文件和main.js文件必须得放在同一目录下,如果不是在使用模块的时候前面还需要加上文件所在相对路径!
3)独立模块(不依赖任何模块)---为了方便我们下面统一使用匿名模块的定义方式,即使用文件名代表定义的模块
a.js文件(定义模块)
define(function(){
return{
name:"zhansan",
age:28,
eat:function(){
console.log(this.name+"正在吃饭!")
}
}
})
main.js(使用模块)
require(['module1'],function(m1){
m1.eat();
})
细心的朋友可能会发现上面的代码其实与2)中的代码机会一模一样,唯一的区别就是我们在定义莫块的时候直接省略了第二个参数,即定义模块时不依赖任何其他模块,这种定义方式我们就称为独立模块!
4)非独立模块
a.js文件(定义模块)
define("module1",["jquery"],function(jq){
return{
name:"zhansan",
age:28,
eat:function(){
console.log(this.name+"正在吃饭!")
}
}
})
main.js(使用模块)
require(['module1'],function(m1){
m1.eat();
})
非独立模块就更简单了,代码和2)完全一模一样,即定义模块时用到的其他模块,我们需要在第二个参数的数组里面进行声明,并在第三个参数里面起个别名,供函数里面使用!
下面我们来详细说一下第三个参数 module-factory-or-object,这个参数其实就是定义模块时写模块逻辑的地方,它的数据格式一般分为两种,js函数或者js对象,下面我们举例说明:
如果是一个对象,那么它可能是一个包含方法具有功能的一个对象;也有可能是仅提供数据。后者和JSON-P非常类似,因此AMD也可以认为包含了一个完整的 JSON-P实现。模块演变为一个简单的数据对象,这样的数据对象是高度可用的,而且因为是静态对象,它也是CDN友好的,可以提高JSON-P的性能。考虑一个提供中国省市对应关系的JavaScript对象,如果以传统JSON-P的形式提供给客户端,它必须提供一个callback函数名,根据这个函数名动态生成返回数据,这使得标准JSON-P数据一定不是CDN友好的。但如果用AMD,这个数据文件就是如下的形式:
define({
provinces: [
{
name: '上海',
areas: ['浦东新区', '徐汇区']},
{
name: '江苏',
cities: ['南京', '南通']}
//.....
]
});
假设这个文件名为china.js,那么如果某个模块需要这个数据,只需要:
define(['china', function(china){
//在这里使用中国省市数据
});
通过这种方式,这个模块是真正高度可复用的,无论是用远程的,还是Copy到本地项目,都节约了开发时间和维护时间。
如果参数是一个函数,其用途之一是快速开发实现。适用于较小型的应用,你无需提前关注自己需要什么模块,自己给谁用。在函数中,可以随时require自己需要的模块。例如:
define(function(){
var p = require('china');
//使用china这个模块
});
即你省略了模块名,以及自己需要依赖的模块。这不意味着你无需依赖于其他模块,而是可以让你在需要的时候去require这些模块。define方法在执行的时候,会调用函数的toString方法,并扫描其中的require调用,提前帮助你载入这些模块,载入完成之后再执行。这使得快速开发成为可能。需要注意的一点是,Opera不能很好的支持函数的toString方法,因此,在浏览器中它的适用性并不是很强。但如果你是通过build工具打包所有的 JavaScript文件,这将不是问题,构建工具会帮助你扫描require并强制载入依赖的模块。
备注:define ({method1:function(){
alert("方法1被调用")
},
method2function(){
alert("方法2被调用")
}
})
等价于:
define (function(){
return{
method1:function(){
alert("方法1被调用")
},
method2:function(){
alert("方法2被调用")
}
}
})
多数情况下我们采用第二种写法,因为我们在真实操作的时候可能会进行一些逻辑运算或者数据初始化工作,直接返回对象的方式不能做这些工作。 特别注意;define定义模块时,返回的结果不局限于对象,可以为任意数据格式!-----------------------------------------------------------------------------------我是分割线-------------------------------------------------------------------------------------------------------------------------------------
require:使用模块关键字
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
require()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
下面,我们看一个实际的例子。
假定主模块依赖jquery、underscore和backbone这三个模块,main.js就可以这样写:
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
require.js会先加载jQuery、underscore和backbone,然后再运行回调函数。主模块的代码就写在回调函数中。