js模块化
es6
定义了新的模块标准化,提供了modules
export xxx;
import xxx from file
没有采用nodejs的CommonJS,
没有实现require,
require和module.exports只是node的私有全局方法和对象属性
建议写法:
export {fun as default,a,b,c};
nodejs
模块的规范是CommonJS
module.exports = data; var data = require(file)
commonjs 对应 浏览器,nodejs的概念位置
|---------------浏览器----- ------------------| |--------------------------CommonJS----------------------------------|
| BOM | | DOM | | ECMAScript | | FS | | TCP | | Stream | | Buffer | |........|
|-------W3C-----------| |---------------------------------------Node--------------------------------------------------|
CommonJS 是同步加载模块
var math = require('math'); //(同步) math.js 引去进来后,才会执行后面的add,文件都在磁盘上,同步没有任何问题
math.add(2,3); // 5
浏览器也能用
其为nodejs专有,由于浏览器没有全局变量module、require等,不过可以借助一些工具完成浏览器端的实现,
其原理是现将所有模块都定义好并通过 id
索引,这样就可以方便的在浏览器环境中解析了,
如:Browserify
// foo.js module.exports = function(x) { console.log(x); }; // main.js var foo = require("./foo"); foo("Hi");
$ browserify main
.js > compiled.js
$ browser
-unpack < compiled.js
[ { "id":1, "source":"module.exports = function(x) {\n console.log(x);\n};", "deps":{} }, { "id":2, "source":"var foo = require(\"./foo\");\nfoo(\"Hi\");", "deps":{"./foo":1}, "entry":true } ]
执行的时候,浏览器遇到 require('./foo') 语句,就自动执行1号模块的 source 属性,并将执行后的 module.exports 属性值输出。
CommonJS 已经过时,Node.js 的内核开发者已经废弃了该规范。
现在用了webpack和babel编译
es6的import 是编译时的,选择import的内容编译进来,性能更好
commonjs的require是运行时的,运行的时候,会执行require 模块后赋值给某个变量
目前不管是nodejs中,还是写前端代码,为了支持es6都是用babel编译,babel其实是把把es6转成es5,import编译成require,
所以用babel编译的代码可以混搭 import和require
浏览器端
为什么commonjs 不适合
CommonJS 是同步加载模块
var math = require('math'); //(同步) 等待math.js 引去进来后,才会执行后面的add,文件都在磁盘上,同步没有任何问题 math.add(2,3); // 5
这时候浏览器端不适合的,js是通过网络加载的,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。
因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这就是AMD规范诞生的背景。
AMD是"Asynchronous Module Definition"的缩写
它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
require(['math'], function (math) { math.add(2, 3);// math 加载好了后执行这句 });
math.add()与math模块加载不是同步的,浏览器不会发生假死。
说白了,js的执行没有提高和改变,主要是不想让加载js影响到代码;所以需要我们换种回调类型的写法,加载好了通过回调执行js,没有谁会因为加载而卡住。
目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。
最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。
<script src="1.js"></script> <script src="2.js"></script> <script src="3.js"></script> <script src="4.js"></script> <script src="5.js"></script> <script src="6.js"></script>
这段代码依次加载多个js文件。
这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
require.js的诞生,就是为了解决这两个问题:
(1)实现js文件的异步加载,避免网页失去响应;
(2)管理模块之间的依赖性,便于代码的编写和维护。
浏览器目前模块化方式
浏览器端有requirejs(AMD)和seajs(CMD)之类的工具包实现模块化,他们写法差不多,执行原理过程有点区别,后面会说
// ----------- AMD or CMD ---------------- define(function(require, exports, module){ module.exports = { a : function() {}, b : 'xxx' }; }); // ------------ AMD or CMD ------------- define(function(require, exports, module){ var m = require('./a'); m.a(); });
AMD(异步模块定义)主要为前端js的表现指定规范
define(id?: String, dependencies?: String[], factory: Function|Object);
id
是模块的名字,它是可选的参数。
dependencies
指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 factory
中。如果没有指定 dependencies
,那么它的默认值是 ["require", "exports", "module"]
。
define(function(require, exports, module) {})
factory
是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。
eg:
定义一个名为 myModule
的模块,它依赖 jQuery
模块:
define('myModule', ['jquery'], function($) { // $ 是 jquery 模块的输出 $('body').text('hello world'); }); // 使用 define(['myModule'], function(myModule) {});
在模块定义内部引用依赖:
define(function(require) { var $ = require('jquery'); $('body').text('hello world'); });
这里有define,把东西包装起来啦,那require.js 和 Node实现中怎么没看到有define关键字呢,它也要把东西包装起来呀,其实吧,只是他们隐式包装了而已
SeaJs和RequireJs区别
SeaJS对模块的态度是懒执行, 而RequireJS对模块的态度是预执行
如下模块通过SeaJS/RequireJS来加载, 执行结果会是怎样?
define(function(require, exports, module) { console.log('require module: main'); var mod1 = require('./mod1'); mod1.hello(); var mod2 = require('./mod2'); mod2.hello(); return { hello: function() { console.log('hello main'); } }; });
先试试SeaJS的执行结果,他是需要的时候执行依赖
require module: main
require module: mod1
hello mod1
require module: mod2
hello mod2
hello main
再来是RequireJS的执行结果,他是 所有的依赖提前执行好了,
require module: mod1
require module: mod2
require module: main
hello mod1
hello mod2
hello main
参考:
AMD http://www.cnblogs.com/chenguangliang/p/5856701.html
Commonjs http://www.cnblogs.com/skylar/p/4065455.html