前端发展到今天,已经有很多模块化的方案,好比前端
CommonJS(经常使用在服务器端,同步的,如nodejs)node
AMD(经常使用在浏览器端,异步的,如requirejs)(Asynchronous Module Definition)程序员
CMD(经常使用在浏览器端,异步的,如seajs)编程
UMD(AMD&& CommonJS) 这些模块化规范的核心价值都是让 JavaScript 的模块化开发变得简单和天然。数组
服务器端模块 在服务器端,全部的模块都存放在本地硬盘,能够同步加载完成,等待时间就是硬盘的读取时间。浏览器
浏览器端模块: 在浏览器端,全部的模块都放在服务器端,同步加载,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。所以,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。缓存
CommonJs 是服务器端模块的规范,Node.js采用了这个规范。 CommonJS 加载模块是同步的,因此只有加载完成才能执行后面的操做。 像Node.js主要用于服务器的编程,加载的模块文件通常都已经存在本地硬盘,因此加载起来比较快,不用考虑异步加载的方式,因此CommonJS规范比较适用。 服务器
CommonJS模块的特色以下: 全部代码都运行在模块做用域,不会污染全局做用域。 模块能够屡次加载,可是只会在第一次加载时运行一次,而后运行结果就被缓存了,之后再加载,就直接读取缓存结果。 模块加载的顺序,按照其在代码中出现的顺序。异步
CommonJS语法async
一、定义模块
根据CommonJS规范,每一个文件就是一个模块,有本身的做用域。在一个文件里面定义的变量、函数、都是私有的,对其余文件不可见。若是想在多个文件分享变量,必须定义为顶层对象的属性,如:global.warning = true;上面代码的warning变量,能够被全部文件读取。固然,这样写法是不推荐的。
二、模块的接口
CommonJS规范规定,每一个模块内部,module变量表明当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,实际上是加载该模块的module.exports属性。
三、加载模块
加载模块使用require方法,该方法读取一个文件并执行,返回文件内部module.exports对象 注:不一样的实现对require时的路径有不一样要求,通常状况能够省略js拓展名,可使用相对路径,也可使用绝对路径,甚至能够省略路径直接使用模块名(前提是该模块是系统内置模块)
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义". RequireJS是一个工具库,主要用于客户端的模块管理。它可让客户端的代码分红一个个模块,实现异步或动态加载,从而提升代码的性能和可维护性。它的模块管理遵照AMD规范。 RequireJS的基本思想是,经过define方法,将代码定义为模块;经过require方法,实现代码的模块加载。 首先,将require.js嵌入网页,而后就能在网页中进行模块化编程了。<script data-main="scripts/main" src="scripts/require.js"></script>上面代码的data-main属性可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。
一、定义模块
define(id?, dependencies?, factory);
id:可选参数,用来定义模块的标识,若是没有提供该参数,脚本文件名(去掉拓展名)
dependencies:是一个数组,表示当前模块的依赖
factory:工厂方法,模块初始化要执行的函数或对象。若是为函数,它应该只被执行一次。若是是对象,此对象应该为模块的输出值
二、加载模块
require([dependencies], function(){}); 第一个参数是一个数组,表示所依赖的模块,第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可使用这些模块
CMD 即Common Module Definition通用模块定义 CMD规范是国内发展出来的,CMD有个浏览器的实现SeaJS 在 CMD 规范中,一个模块就是一个文件。
Sea.js 是一个成熟的开源项目,核心目标是给前端开发提供简单、极致的模块化开发体验。这里很少作介绍,有兴趣的能够查看官方文档。 使用 Sea.js,在书写文件时,须要遵照 CMD (Common Module Definition)模块定义规范。一个文件就是一个模块。 首先要在页面中引入 sea.js 文件,这通常经过页头全局把控,也方便更新维护。想在页面中使用某个组件时,只要经过 seajs.use 方法调用。
CMD语法
一、定义模块define(id?, deps?, factory)
字符串id为模块标识,数组deps为模块依赖; 参数 factory 能够是一个函数,也能够为对象或者字符串。
factory是一个函数,有三个参数: require 是一个方法,接受 模块标识 做为惟一参数,用来获取其余模块提供的接口:require(id) exports 是一个对象,用来向外提供模块接口 module 是一个对象,上面存储了与当前模块相关联的一些属性和方法 注: 带 id 和 deps 参数的 define 用法不属于 CMD 规范,而属于 Modules/Transport 规范。
Sea.js 带来的两大好处: 经过 exports 暴露接口。这意味着不须要命名空间了,更不须要全局变量。这是一种完全的命名冲突解决方案。 经过 require 引入依赖。这可让依赖内置,开发者只需关心当前模块的依赖,其余事情 Sea.js 都会自动处理好。对模块开发者来讲,这是一种很好的 关注度分离,能让程序员更多地享受编码的乐趣。
1.AMD推崇依赖前置。 在定义模块的时候就要声明其依赖的模块; CMD推崇依赖就近,只有在用到某个模块的时候再去require ;
2.AMD依赖模块的执行顺序和书写顺序不必定一致;CMD模块的执行顺序和书写顺序是彻底一致的
3.对于依赖的模块AMD是提早执行,CMD是延迟执行。不过RequireJS从2.0开始,也改为能够延迟执行(根据写法不一样,处理方式不经过)。
UMD (Universal Module Definition)通用模块规范 是AMD和CommonJS二者的结合 这个模式中加入了当前存在哪一种规范的判断,因此可以“通用”,它兼容了AMD和CommonJS,同时还支持老式的“全局”变量规范: 应用UMD规范的js文件其实就是一个当即执行函数。在执行UMD规范时,会优先判断是当前环境是否支持AMD环境,而后再检验是否支持CommonJS环境,不然认为当前环境为浏览器环境( window )。固然具体的判断顺序实际上是能够调换的。
一、更好的分离
若是要加载多个就得放置多个 script 标签,若是是加载模块的话,对于 HTML 和 JavaScript 分离颇有好处,在某些场景下这个分离度很重要。
二、更好的代码组织方式 若是单个文件愈来愈大,维护起来出问题的概率也会愈来愈大,若是是多人开发,不一样的代码风格,超多的业务逻辑混杂在一块儿,不要说维护了,光想一想感受都很麻烦。模块式的开发,一个文件就是一个模块,控制了文件的粒度,每一个模块能够专一于一个功能。
三、按需加载
四、避免命名冲突
五、更好的依赖处理