RequireJS& AMD规范
来源:互联网 发布:淘宝店铺登陆 编辑:程序博客网 时间:2024/06/10 17:28
RequireJS
使用 RequireJS 加载 JavaScript 文件,若有两个 JavaScript 文件 a.js 和 b.js,里面各自定义了 myFunctionA 和 myFunctionB 两个方法,通过下面这个方式可以用 RequireJS 来加载这两个文件,在 function 部分的代码可以引用这两个文件里的方法。
<span style="font-size:10px;"><script src="./js/require.js"></script><script> require(["./js/a.js", "./js/b.js"], function() { myFunctionA(); myFunctionB(); }); </script></span>require 方法里的这个字符串数组参数可以允许不同的值,当字符串是以”.js”结尾,或者以”/”开头,或者就是一个 URL 时,RequireJS 会认为用户是在直接加载一个 JavaScript 文件,否则,当字符串是类似”my/module”的时候,它会认为这是一个模块,并且会以用户配置的 baseUrl 和 paths 来加载相应的模块所在的 JavaScript 文件
RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
首先,将require.js嵌入网页,然后就能在网页中进行模块化编程了。
<scriptdata-main="scripts/main" src="scripts/require.js"></script>
上面代码的data-main属性不可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。
define方法:定义模块
define方法用于定义模块,RequireJS要求每个模块放在一个单独的文件里。
按照是否依赖其他模块,可以分成两种情况讨论。第一种情况是定义独立模块,即所定义的模块不依赖其他模块;第二种情况是定义非独立模块,即所定义的模块依赖于其他模块。
1)独立模块
如果被定义的模块是一个独立模块,不需要依赖任何其他模块,可以直接用define方法生成。
define({
method1: function() {},
method2: function() {},
});
上面代码生成了一个拥有method1、method2两个方法的模块。
另一种等价的写法是,把对象写成一个函数,该函数的返回值就是输出的模块。
define(function () {
return {
method1: function() {},
method2: function() {},
};
});
后一种写法的自由度更高一点,可以在函数体内写一些模块初始化代码。
值得指出的是,define定义的模块可以返回任何值,不限于对象。
2)非独立模块
如果被定义的模块需要依赖其他模块,则define方法必须采用下面的格式。
define(['module1', 'module2'], function(m1, m2) {
...
});
module1模块和module2模块指的是,当前目录下的module1.js文件和module2.js文件,等同于写成['./module1', './module2']。
define方法的第二个参数是一个函数,当前面数组的所有成员加载成功后,它将被调用。它的参数与数组的成员一一对应。这个函数必须返回一个对象,供其他模块调用。
define(['module1', 'module2'], function(m1, m2) {
return {
method: function() {
m1.methodA();
m2.methodB();
}
};
});
上面代码表示新模块返回一个对象,该对象的method方法就是外部调用的接口,menthod方法内部调用了m1模块的methodA方法和m2模块的methodB方法。
需要注意的是,回调函数必须返回一个对象,这个对象就是你定义的模块。
require方法:调用模块
require方法用于调用模块。它的参数与define方法类似。
require(['foo', 'bar'], function ( foo, bar ) {
foo.doSomething();
});
上面方法表示加载foo和bar两个模块,当这两个模块都加载成功后,执行一个回调函数。该回调函数就用来完成具体的任务。
require方法也可以用在define方法内部。
define(function (require) {
var otherModule = require('otherModule');
});
What should you do with many dependencies:
To make this easier, and to make it easy to do a simple wrapping around CommonJS modules, this form of define is supported, sometimes referred to as "simplified CommonJS wrapping":
define(function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
The AMD loader will parse out the require('') calls by using Function.prototype.toString(), then internally convert the above define call into this:
define(['require', 'dependency1', 'dependency2'], function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
AMD模式小结
define和require这两个定义模块、调用模块的方法,合称为AMD模式。它的模块定义的方法非常清晰,不会污染全局环境,能够清楚地显示依赖关系。
AMD模式可以用于浏览器环境,并且允许非同步加载模块,也可以根据需要动态加载模块
require方法本身也是一个对象,它带有一个config方法,用来配置require.js运行参数。config方法接受一个对象作为参数require方法本身也是一个对象,它带有一个config方法,用来配置require.js运行参数。config方法接受一个对象作为参数。
require.config({
paths: {
jquery:['//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js','lib/jquery']
}
});
config方法的参数对象有以下主要成员:
(1)baseUrl
<script>
require.config({
baseUrl: "/another/path",
paths: {
"some": "some/v1.0"
},
waitSeconds: 15
});
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
//该函数会在上述所有的依赖加载完毕后调用。
//注意该函数可在页面加载完毕前被调用。
//本回调函数是可选的。
}
);
</script>
所有模块的查找根路径。所以上面的示例中,"my/module"的标签src值是"/another/path/my/module.js"。当加载纯.js文件(依赖字串以/开头,或者以.js结尾,或者含有协议),不会使用baseUrl。因此a.js及b.js都在包含上述代码段的HTML页面的同目录下加载。
如未显式设置baseUrl,则默认值是加载require.js的HTML所处的位置。如果用了data-main属性,则该路径就变成baseUrl。
baseUrl可跟require.js页面处于不同的域下,RequireJS脚本的加载是跨域的。
(2)paths
path映射那些不直接放置于baseUrl下的模块名。设置path时起始位置是相对于baseUrl的,除非该path设置以"/"开头或含有URL协议(如http:)。在上述的配置下,"some/module"的script标签src值是"/another/path/some/v1.0/module.js"。
用于模块名的path不应含有.js后缀,因为一个path有可能映射到一个目录。
paths备错配置:
requirejs.config({
paths: {
jquery: [
'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
//若CDN加载错,则从如下位置重试加载
'lib/jquery'
]
}
});
require(['jquery'], function ($) {
});
上述代码先尝试加载CDN版本,如果出错,则退回到本地的lib/jquery.js。
(3)shim
有些库不是AMD兼容的,这时就需要指定shim属性的值。shim可以理解成“垫片”,用来帮助require.js加载非AMD规范的库。
require.config({
paths: {
"backbone": "vendor/backbone",
"underscore": "vendor/underscore"
},
shim: {
"backbone": {
deps: [ "underscore" ],
exports: "Backbone"
},
"underscore": {
exports: "_"
}
}
});
上面代码中的backbone和underscore就是非AMD规范的库。shim指定它们的依赖关系(backbone依赖于underscore),以及输出符号(backbone为“Backbone”,underscore为“_”)。
(4)map
对于给定的模块前缀,使用一个不同的模块ID来加载该模块。
该手段对于某些大型项目很重要:如有两类模块需要使用不同版本的"foo",但它们之间仍需要一定的协同。
requirejs.config({
map: {
'some/newmodule': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
如果各模块在磁盘上分布如下:
· foo1.0.js
· foo1.2.js
· some/
o newmodule.js
o oldmodule.js
当“some/newmodule”调用了“require('foo')”,它将获取到foo1.2.js文件;而当“some/oldmodule”调用“require('foo')”时它将获取到foo1.0.js。
该特性仅适用于那些调用了define()并将其注册为匿名模块的真正AMD模块脚本。并且,请在map配置中仅使用绝对模块ID,“../some/thing”之类的相对ID不能工作。
另外在map中支持“*”,意思是“对于所有的模块加载,使用本map配置”。
(5)Packages
RequireJS支持从CommonJS包结构中加载模块,但需要一些额外的配置。具体地,支持如下的CommonJS包特性:
1.一个包可以关联一个模块名/前缀。
2.package config可为特定的包指定下述属性:
name:包名(用于模块名/前缀映射)
location: 磁盘上的位置。位置是相对于配置中的baseUrl值,除非它们包含协议或以“/”开头。
main:当以“包名”发起require调用后,所应用的一个包内的模块。默认为“main”。
而下面的示例中使用了两个包,cart及store:
· project-directory/
o project.html
o cart/
§ main.js
o store/
§ main.js
§ util.js
o main.js
o require.js
main.js使用“packages”配置项来设置相对于require.js的各个包,此例中是源码包“cart”及“store”:
//main.js的内容
//传递一个config object到require
require.config({
"packages": ["cart", "store"]
});
require(["cart", "store", "store/util"],
function (cart, store, util) {
//正常地使用模块
});
对“cart”的依赖请求会从scripts/cart/main.js中加载,因为“main”是RequireJS默认的包主模块。对“store/util”的依赖请求会从scripts/store/util.js加载。
(6)deps
指定要加载的一个依赖数组。当将require设置为一个config object在加载require.js之前使用时很有用。一旦require.js被定义,这些依赖就已加载。使用deps就像调用require([]),但它在loader处理配置完毕之后就立即生效。它并不阻塞其他的require()调用,它仅是指定某些模块作为config块的一部分而异步加载的手段而已。
AMD 规范
异步模块定义(AMD)的编程接口提供了定义模块,及异步加载该模块的依赖的机制。它非常适合于使用于浏览器环境,浏览器的同步加载模块机制会带来性能,可用性,调试和跨域访问的问题。
API 说明
define() 函数
本规范只定义了一个函数 "define",它是全局变量。函数的描述为:
define(id?, dependencies?, factory);
名字
第一个参数,id,是个字符串,它指的是定义中模块的名字,这个参数是可选的。如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。
模块名的格式
模块名用来唯一标识定义中模块,它们同样在依赖性数组中使用。AMD的模块名规范是是CommonJS模块名规范的超集。引用如下:
· 模块名是用正斜杠分割的有意义单词的字符串
· 单词须为驼峰形式,或者".",".."
· 模块名不允许文件扩展名的形式,如“.js”
· 模块名可以为 "相对的" 或 "顶级的"。如果首字符为“.”或“..”则为相对的模块名
· 顶级的模块名从根命名空间的概念模块解析
· 相对的模块名从 "require" 书写和调用的模块解析
CommonJS模块id属性常被用来JavaScript模块。
依赖
第二个参数,dependencies,是个定义中模块所依赖模块的数组。依赖模块必须根据模块的工厂方法优先级执行,并且执行的结果应该按照依赖数组中的位置顺序以参数的形式传入(定义中模块的)工厂方法中。
依赖的模块名如果是相对的,应该解析为相对定义中模块。换句话来说,相对名解析为相对于模块的名字,并非相对于寻找该模块的名字的路径。
本规范定义了截然不同的三种特殊的依赖关键字。如果"require","exports", 或 "module"出现在依赖列表中,参数应该按照CommonJS模块规范自由变量去解析。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数指定的参数个数 调用工厂方法。
工厂方法
第三个参数,factory,为模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
如果工厂方法返回一个值(对象,函数,或任意强制类型转换为true的值),应该为设置为模块的输出值。
简单的 CommonJS 转换
如果依赖性参数被忽略,模块加载器可以选择扫描工厂方法中的require语句以获得依赖性(字面量形为require("module-id"))。工厂函数第一个参数必须为require,从而使此机制正常工作。
在某些情况下,因为脚本大小的限制或函数不支持toString方法(Opera Mobile是已知的不支持函数的toString方法),模块加载器可以选择不扫描依赖性。
如果有依赖参数,模块加载器不应该在工厂方法中扫描依赖性。
define.amd 属性
为了清晰的标识标识全局函数(为浏览器加载script必须的)遵从AMD编程接口。任何全局函数应该有一个"amd"的属性,它的值为一个对象。这样可以防止与现有的定义了define函数但不遵从AMD编程接口的代码相冲突。
当前,define.amd对象的属性没有包含在本规范中。实现本规范的作者,可以用它通知超出本规范编程接口基本实现的额外能力。
define.amd的存在表明函数遵循本规范。如果有另外一个版本的编程接口,那么应该定义另外一个属性,如define.amd2,表明实现只遵循该版本的编程接口。
一个如何定义同一个环境中允许多次加载同一个版本的模块的实现:
define.amd = {
multiversion: true
};
The minimum definition:
define.amd = {};
一次输出多个模块
在一个脚本中可以使用多次define调用。这些define调用的顺序不应该是重要的。早一些的模块定义中所指定的依赖,可以在同一脚本中晚一些定义。这被模块加载器用来延迟加载未解决的依赖,直到全部脚本加载完毕,防止没必要的请求。
例子
使用 require 和 exports
创建一个名为"alpha"的模块,使用了require,exports,和名为"beta"的模块:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
一个返回对象的匿名模块:
define(["alpha"], function (alpha) {
return {
verb: function(){
return alpha.verb() + 2;
}
};
});
一个没有依赖性的模块可以直接定义对象:
define({
add: function(x, y){
return x + y;
}
});
一个使用了简单CommonJS转换的模块定义:
define(function (require, exports, module) {
var a = require('a'),
b = require('b');
exports.action = function () {};
});
全局变量
本规范保留全局变量"define"以用来实现本规范。包额外信息异步定义编程接口是为将来的CommonJS API保留的。模块加载器不应在此函数添加额外的方法或属性。
本规范保留全局变量"require"被模块加载器使用。模块加载器可以在合适的情况下自由地使用该全局变量。它可以使用这个变量或添加任何属性以完成模块加载器的特定功能。它同样也可以选择完全不使用"require"。
与CommonJS的关系
AMD可以作为一个中转的版本作为CommonJS模块只要CommonJS没有被用来同步的require调用。使用同步require调用的CommonJS代码可以被转换为使用回调风格的AMD模块加载器。
- RequireJS& AMD规范
- RequireJS和AMD规范
- RequireJS和AMD规范
- requireJs AMD规范
- AMD规范与requireJS
- RequireJS和AMD规范
- AMD规范&RequireJs基础
- RequireJS和AMD规范
- requirejs中非AMD规范js的加载
- JS加载文件规范,AMD,commonJS,requireJs
- RequireJS以及AMD规范入门实践
- requirejs加载远程非AMD规范js及和seajs规范CMD比较
- AMD&CMD&CommonJS&RequireJS
- 使用requireJS加载不符合AMD规范的js文件:shim的使用方式和实现原理
- 使用requireJS加载不符合AMD规范的js文件:shim的使用方式和实现原理
- 使用requireJS加载不符合AMD规范的js文件:shim的使用方式和实现原理
- 使用requireJS加载不符合AMD规范的js文件:shim的使用方式和实现原理
- AMD规范
- 取当前用户的AppData路径
- 由浅入深linux嵌入式ARM开发视频教程学习笔记
- 用CreateProcess API函数来创建相应的进程
- 怎样禁止下拉通知栏
- swift中得?和!笔记
- RequireJS& AMD规范
- JX8NET 教你用 Spark Resilient Distributed Dataset
- 带鉴权信息的SIP呼叫
- 不解释 备用
- 2014年还在做SEO的朋友 你OUT了!
- Eclipse更改workspace路径设置
- 各种光照的算法原理 菲涅尔法则
- oracle分析索引,重建--分析表
- 网络请求,HTTP协议 ,GET,POST