在 模块化开发
开发之前,都是直接在页面上引入 script
标签来引用脚本的,当项目变得比较复杂,就会带来不少问题。javascript
因而,AMD 规范就诞生了,AMD 即为异步模块定义,有效避免同步加载致使页面的假死现象。RequireJS 是一个 AMD 的实现,后来还有CMD规范,玉伯的 而SeaJS 是 CMD 的一个实现,二者最大的区别就是html
RequireJS 是预加载,而sea.js 是懒加载,也就是按需加载java
什么意思 ??jquery
好比下面的代码数组
define(function(require,exports,module){ // do something var mod1 = require('./mod1'); // do something var mod2 = require('./mod2'); })
RequireJS 会所有找到这个模块的依赖,并在开始执行是就加载所有的依赖,
而SeaJS 则是按需加载,直到遇到 require 才会加载。浏览器
RequireJS 内部经过
Function.prototype.toString()
,而后使用正则匹配全部的require 方法,将其转化为app
define(['./mod1',./mod2']function(mod1,mod2)
这种方式。异步
有不少关于这两种方式的争吵,因为我没有作过较大的项目,因此对于这两种方式在正真项目中使用的区别也不清楚。模块化
主要接口有两个: require
& define
,define 是模块的定义方法,require 是模块的使用方法。
define 的参数为 define (id?,deps?,factory)
。第一个为模块ID,第2个为依赖列表,第三个是工厂方法 。若是不定义ID,则为匿名方法,一般状况,模块ID 等于模块在工程的路径。deps 和 factory 有约定,deps 数组有多少个元素,factory 就会有多少个形参,形参对于与依赖模块工厂函数执行后的返回值。函数
define ("id",["mod1","mod2"],function(mod1,mod2){ return { /// }; })
require 方法和 define 基本一致。
文件目录
└─ use-require/ ├─ app/ │ ├─ js/ │ │ ├─ module/ │ │ │ ├─ a.js │ │ │ └─ b.js │ │ ├─ main.js │ └─ lib/ │ │ └─ require.js ├─ index.html └─ readme.md
如今,须要在 index.html 引导整个程序 。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src="./app/lib/require.js" data-main="./app/js/main"> </script> </body> </html>
引入 requirejs,并经过 data-main
申明 启动 js 文件。
注意: data-main 指向的文件所在路径就是 baseUrl,在这里就是app/js ,
baseUrl 也能够经过require.config 设置 。若是没有经过 data-main 属性指定 baseUrl ,也没有经过config的方式显示声明 baseUrl ,那么 baseUrl 默认为加载requirejs的那个页面所在的路径
下面 b 依赖 a ,那么就应该写module/a
,而 main 依赖 b ,写为module/b
,这个路径会和 baseUrl 拼接,与a ,b 所在的路径无关 。有时候,你可能须要生成一个相对于模块的URL地址。你能够将require
做为一个依赖注入进来,而后调用require.toUrl()
以生成该URL 。
define(["require"], function(require) { var url = require.toUrl("./style.js"); });
有时候你想避开"baseUrl + paths"的解析过程,而是直接指定加载某一个目录下的脚本。此时能够这样作:若是一个module ID符合下述规则之一,其ID解析会避开常规的"baseUrl + paths"配置,而是直接将其加载为一个相对于当前HTML文档的脚本:
注意是 相对于 HTML 文档,由于 js脚本是会被插入到 html 文档中执行的 。
通常来讲,最好仍是使用baseUrl及"paths" config去设置module ID。它会给你带来额外的灵活性,如便于脚本的重命名、重定位等。 同时,为了不凌乱的配置,最好不要使用多级嵌套的目录层次来组织代码,而是要么将全部的脚本都放置到baseUrl中,要么分置为项目库/第三方库的一个扁平结构,以下:
└─ project/ ├─ js/ │ ├─ app/ │ │ └─ sub.js │ ├─ lib/ │ │ ├─ jquery.js │ │ └─ require.js │ └─ app.js ├─ index.html └─ readme.md
下面天然就顺利成章
申明模块a
define(function() { 'use strict'; return { name: "hello , i am a" } })
模块 b
define(["module/a"], function(a) { 'use strict'; var aName = a.name; var name = "hello i am b"; return { sayHello: function() { console.log(name + " my brother is " + aName); } } })
在模块b 里面依赖模块a 。
main.js
require(["module/b"], function(b) { 'use strict'; b.sayHello(); })
看看效果
若是使用 require.config()
配置呢?
将上面的目录复制一份,命名 use-require-config
,目录结构彻底一致
main.js
requirejs.config({ baseUrl: './app/js/module' }) require([".b"], function(b) { 'use strict'; b.sayHello(); })
在这里,将配置放在 main.js 里面,等会儿会讲若是不放在它里面会又什么问题。
模块 b 依赖 于 a
define(["./a"], function(a) { 'use strict'; var aName = a.name; var name = "hello i am b"; return { sayHello: function() { console.log(name + " my brother is " + aName); } } })
因为将
baseUrl
设置为app/js/module
,因此这里依赖a
就能够直接写a
在这里,我使用./a
, 与直接写a
如出一辙,仍是使用baseUrl+ moduleName
`来寻找模块路径。
若是不将 requirejs.config
放在main中,而是另外在引入一个script 节点来放置 呢
<body> <script src="./app/lib/require.js" data-main="./app/js/main"> </script> <script> requirejs.config({ baseUrl: './app/js/module' }) </script> </body>
在浏览器运行
发现报错了,怎么回事呢?
看它寻找 main.js 的路径
file:///E:/HFLib/module/code/use-require-config/app/js/module/main.js
是 baseUrl + main.js。 这说明,配置的 baseUrl 覆盖了为 data-main 配置的路径
也就是说,一旦使用requirejs.config 来配置 baseUrl,那么全部的路径都会以 baseUrl 为基准。
因此,data-main 应改成: ..\main
,注意这里必需要使用反斜杠,正斜杠拼接老是会出现问题。
经过这样就能够解决 data-main 和 requirejs.config() 的冲突了 。
paths 和 shim 。
当模块名过长是,require.js 为咱们提供了路径 paths 的方式 。
理想情况下,每一个加载的脚本都是经过define()来定义的一个模块;但有些"浏览器全局变量注入"型的传统/遗留库并无使用define()来定义它们的依赖关系,你必须为此使用shim config来指明它们的依赖关系。
这是个人文件目录
index.html
<body> <script src="./app/lib/require.js" data-main="./app/main"> </script> </body>
main.js
requirejs.config({ paths: { jQuery: 'lib/jQuery' }, shim: { 'jQuery': { exports: '$' } } }) require(['jQuery'], function($) { 'use strict'; console.log($); })
能够看到,已经顺利注入了 jQuery 依赖。
require.js 中还有不少配置和用法,我用的就比较少,就简单介绍到这里。
下来,我要实现一个简化的模块加载器,相似于 require.js.
太晚了 。
就在 实现一个本身的模块加载器(二)中实现一个相似 require.js 的Demo 吧 。