模块机制 之commonJs、node模块 、AMD、CMD

  在其余高级语言中,都有模块中这个概念,好比java的类文件,PHP有include何require机制,JS一开始就没有模块这个概念,起初,js经过<script>标签引入代码的方式显得杂乱无章,语言自身也缺少组织和约束能力,因此人们不得不以各类命名空间等方式认为的约束代码,达到安全易用的目的。经历十几年的发展,js也执行起了响应的规范,commonJS规范的提出算是一个重要的里程碑。javascript

1、commonJS规范html

  commonJS规范的愿景是但愿JavaScript能在任何地方上运行,出发点主要是想弥补起初没有模块系统、标准库较少、没有标准接口,缺少包管理器等缺陷,但愿JavaScript能够具有和java等语言具有的开发大型应用能力的能力。它为JavaScript开发大型应用程序指明了一条很是好的道路,node正是借鉴这个的规范慢慢的出如今人们的视野中,且逐渐变得强大。前端

  commonJS对模块的定义十分简单,主要分为模块引用、模块定义、模块标识几个部分。java

根据这个规范,每一个文件就是一个模块,有本身的做用域。在一个文件里面定义的变量、函数都是私有的,对其余文件不可见。这个规加载的模块是同步的,加载完成才能执行后面的操做。node

该规范主要是经过 module.exports向外提供接口,加载某个模块,实际上是加载该模块的module.exports属性。c++

//test1.js    模块文件
var a=10;
var dosomething = function(){
     /**代码**/
}
//模块定义 module.exports.a = a; module.exports.dosomething = dosomething; var test2 = require('./test1.js'); //模块引用 其中./test1.js就是模块标识 console.log(test1.a); console.log(test1.dpsomething());//调用test1完成以后,就能够去使用test1所暴露出来的接口(变量) 

特色:git

  一、全部代码都运行在模块做用域,不会污染全局做用域。github

  二、模块能够屡次加载,可是只会在第一次加载时运行一次,而后运行结果就被缓存了,之后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。后端

  三、模块加载的顺序,按照其在代码中出现的顺序。浏览器

  四、便于服务器端和桌面应用使用。

缺点:

  由于该规范加载模块是同步的,浏览器获取一个资源是经过发送http请求以后得到的,这意味着会出现阻塞加载,从而在浏览器进程出现假死现象。因此浏览器须要的是异步加载的规范,这这是下面所讲的AMD和CMD规范。

2、node模块

node在实现模块的实现中并不是彻底按照commonJS规范实现,而是对上面模块规范作了必定的取舍,同时也增长了自身须要的特性。node在实现exports、require、module主要经历几个过程

  一、路径分析 二、文件定位 三、编译执行

node中的模块主要分为两类,一类是nodet提供的核心模块,如fs 、http等模块; 一类是用户编写的文件模块。

核心模块在node代码编译的过程当中,编译成了二进制执行文件,在node进程启动时候,部分核心模块被加载进内存中,因此核心模块在引入时候,文件定位和编译执行能够省略掉,并在路径分析中被优先判断,因此加载的速度是十分快的。

 

几个特色

  一、优先从缓存中加载

        node对引入的模块都会进行缓存,减小二次开销。和浏览器缓存静态脚本不同的是,浏览器缓存的是文件,node缓存的是编译和执行以后的文的对象。因此require()方法对相同的模块一概采用缓存优先的策略。

        二、核心模块是有c/c++和JavaScript编写部分,c/c++在node目录下的src下,JavaScript在lib目录下。编译的过程是讲JavaScript模块文件编译成c/c++代码,在引入核心模块的过程当中,对模块代码进行了从头至尾的包装,让require、module、exports这些变量可以使用,最后执行和处处exports对象。

        三、b包管理机制 

        node组织了自身的核心模块,也使得第三方的文件模块均可以有序的编写和使用,可是在第三方模块中,模块之间散列在各地,不能相互应用,在模块以外,包和NPM是讲各类模块联系起来的一种机制。

3、模块的侧重点

  在JavaScript和node出现以后,一些模块能够在先后端实现公用,先后端的js分别搁置在HTTP的两端,扮演的角色也不同,浏览器的js须要从服务器分发到多个客户端执行,而服务端则是相同的代码屡次执行,前者瓶颈在于宽带,后者在于CPU和内存等资源,前者经过网路读取,后者经过磁盘读取速度显而易见,因此node模块引入几乎是同步的,可是,若是前端的额代码也是采用同步当时引用,这样可能由于UI须要等待脚本的加载,这样就会影响用户的体验,这样commonJS的同步加载就不能知足前端的应用市场了,必须须要其余的加载模式,这样AMD和CMD就营运而生了。

4、AMD

  AMD(asynchronous module define)异步加载定义,该规范是RequireJS 在推广过程当中对模块定义的规范化产出的,是commonJS的一个延伸。

AMD模块须要define来肯定一个模块,用require()加载模块。而node中是隐士包装的,他们的目的都是达到做用域的隔离,仅在须要的时候被引入。

异步的模块加载不影响后面语句的执行,全部依赖这个模块的语句,都定义在一个回调函数中,等到加载完成以后,这个回调函数才会运行。

//定义模块 
define("c", ["a", "b"], function(a, b) { //c:模块id a和b是模块的依赖 都是可选的 a.dosomething(); //加载依赖模块a完成以后执行回调 }); //用require加载模块 require(['c'], function ( c) { // 这里写其他的代码 c.doSomething(); });

 

5、CMD

通用模块定义,该规范是SeaJS 在推广过程当中对模块定义的规范化产出的,有兴趣能够看《前端代码模块加载器之sea,js》。 和AMD很相似,

require, exports, module经过形参的形式传递给模块,在须要模块的时候,随时调用require()去调用。

c是模块的名称,['a']是依赖项,这两个可省略,通常是省略的。
define('c',['a'],function(require, exports, module) { // 模块代码 });

若是b模块中想引用a模块,只需require()就能够了
define(function(require,exports,module){
var a = require('a')
});

  

6、AMD和CMD的区别

  一、对于依赖模块,AMD是依赖前置,CMD依赖就近

// AMD 
 define(['./a', './b'], function(a, b) { 
   // 依赖必须一开始就写好   
    a.doSomething()    
    /******代码*******/
    b.doSomething()    ...
 })

// CMD
define(function(require, exports, module) {
    var a = require('./a') 
    a.doSomething() 
    /******代码*******/
    var b = require('./b') // 依赖能够就近书写   
    b.doSomething()   // ... 
 })

 

  二、执行顺序

  AMD是提早执行,CMD是延迟执行

  三、提供的API

  AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。
  AMD 里,require 分全局 require 和局部 require,都叫 require。
  CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每一个 API 都简单纯粹。

 

为了更好理解不一样模块化开发理念,建议参考:RequireJs和seaJs的差异

7、兼容多种模块规范

为了让一个模块可有运行在先后端,保持先后端的一致性,以下就是展现将test()方法定义到不一样的环境中,它可以兼容node 、AMD、CMD及常规的浏览器中:

;(function(name, definition){
		//检测上下文环境是否是AMD或CMD
		var hasDefined = typeof defined == 'function',
		    //检测上下文环境是否是node
		    hasExports =typeof module !=='undefined' && module.exports;

		    if(hasDefined){
		    	defined(definition); //AMD或CMD
		    }else if( hasExports){
		    	module.exports = definition(); //node
		    }else{
		    	this[name] = definition();   //将执行的结果挂在window变量中,浏览器中的this这指向window
		    }
	})('test',function(){
		var test = function(){}
		return test; 		
	})

  

 简洁点:

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
	typeof define === 'function' && define.amd ? define(['exports'], factory) :
	(factory((global)));
}(this, (function (exports) { 
   'use strict';
    //code
})));    
相关文章
相关标签/搜索