今天学习了一下模块化开发的规范AMD和CommonJS, 整理一下所学也希望大家能一同学习探讨。
AMD和CMD是什么
AMD是RequireJS推广过程中对模块的规范化,理念是依赖前置,速度快、会浪费资源;
CMD是SeaJS推广过程中对模块的规范化,理念是依赖就近,性能较差,只有使用时才加载。
RequireJS、Sea.js、curl.js都属于脚本加载器,就是以一种规范的形式去加载存在依赖的js文件们。而各个脚本加载器是如何实现依赖传递的也是我想再深入学习的..
在这两种规范中,有两个非常重要基础的方法: define方法
用于定义模块,require方法
用于依赖加载,两者在语法上是一致的,但执行顺序不同所以代码设计会有所不同。
我刚开始试的一个错误例子(RequireJS下测试)
//fun.js
define([],function(){
function fun_a(){
console.log("I am fun_a");
};
function fun_b(){
console.log("I am fun_b");
};
function fun_c(){
console.log("I am fun_c");
};
return {
a:fun_a,
b:fun_b
}
});
//main.js
var fun = require('./fun');
fun.a();
//index.html
<script src="http://cdn.bootcss.com/require.js/2.1.22/require.min.js" data-main="main"></script>
然后报了个错.. WTF
在官网上的解释是require('name')这种写法,只应该出现在define()或者require()的回调函数中。
好的吧。
//main.js
require(['fun'],function(fun){
fun.a();
});
喔,对了。
define的完整格式是
define(
module_id, /\*可选,不写的情况下默认是文件名\*/
[dependenices], /\*可选\*/
definition function
);
require的模块加载有require.config()方法.
require.config({
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min"
}
});
依赖前置和依赖就近
RequireJS采用依赖前置,举个例子就是炒菜前一次性把所有食材洗好,切好,根据内部逻辑把有些酱料拌好,最后开始炒菜,前面任何一个步骤出现问题都能较早发现错误;SeaJS的依赖就近就是要炒青椒了去切青椒要炒肉了去切肉,as lazy as possible.
谁好谁坏我也不清楚,个人是比较喜欢require一些,能更早发现错误。
CommonJS
公认用在服务器端(如Node)的模块化规范,主要包含一个自由变量exports
包涵模块希望提供给其他模块的对象、和一个函数require
用于导入其他模块的导出。
一个简单的例子
var $ = require('jquery');
function a(){};
function b(){};
function c(){}; // 私有方法
module.exports = {
a:a,
b:b
}
CommonJS与AMD(为什么Commonjs适用服务器端、AMD适用浏览器)
我觉得根本原因在于浏览器端资源在服务器,而服务器端资源在本地硬盘。一方面AMD没有涉及io、system这些、而且是异步的,服务器上资源下载慢所以异步是必然的,但是本地资源下载是非常快的CommonJS的同步就非常适合。这是为什么AMD不适合服务器端。
CommonJS在浏览器端不合适是因为它的cjs模块只能导出对象!!exports导出的只能是对象,不能像AMD那样方便快捷获取构造器、使用各种插件。更何况CommonJS是同步的,不符合浏览器端的特性。
什么还有UMD !
UMD兼容了AMD和CommonJS,同时还支持老式的“全局”变量规范。
怎么说,太丑我就了解了一下..
各种脚本加载器和框架
支持AMD的
浏览器端:RequireJS、curl.js、bdLoad、Yabble、PINF
服务器端:RequireJS、PINF
支持CJS的
一个CJS模块是一段可重用的JavaScript. CommonJS采用的就是CJS模块.
浏览器端:curl.js、sproutCore、PINF
服务器端:Node、Narwhal、Persevere、Wakanda