@frank-shaw
2017-02-15T15:14:42.000000Z
字数 3145
阅读 2300
javaScript
模块化的趋势:
因为上面的几个原因,导致了我们需要对我们的代码有一个更好的组织形式。模块系统就提供了一种选择:可以将你的一大坨代码分装为多个不同的模块。
有很多不同的模块系统形式,我们来看看概览:
如果你不使用模块系统,那么通常在index.html中就需要写下类似下面的代码:
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
这个就是最原始的JavaScript文件加载方式。如果把每个文件都看成是一个模块,那么它们的接口如果依照上述方式来布置的话,那么就会暴露在全局作用域下,也就是定义在window对象中。我们从JavaScript的学习中可以知道:除非必要,否则不要在全局作用域中定义变量或对象。
这种原始的加载方式的弊端:
我们先来了解:为什么会有CommonJS规范?
我们知道组成JavaScript的重要规范(包括ECMAScript、DOM、BOM等)都是针对web浏览器环境的。并没有合适的针对在服务器环境中使用JavaScript的规范。伴随着NodeJS这一类使用JavaScript来开发服务器的语言的火热,那么就需要有这样一种针对服务器环境的使用JavaScript的规范。CommonJS 是以在浏览器环境之外构建 JavaScript生态系统为目标而产生的项目,比如在服务器和桌面环境中。
那么我们也大概能够知道:CommonJS中的模块规范主要是在服务器端使用模块化。该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口。
一个很重要的名词是同步加载。
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
熟悉nodeJS的开发者应该对这一套规范的使用非常熟悉。但是一切的前提都是在服务器端使用,那么就意味着并不适合在浏览器端来使用,同时“同步加载”对于浏览器而言并不合适。下面来简单说说其优缺点:
优点:
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
AMD全称Asynchronous Module Definition,即异步模块定义。它的主要思想是异步加载模块,那么它显然更加适合在浏览器端使用。
AMD规范其实只有一个主要接口 define(id?, dependencies?, factory)
,它要在声明模块的时候指定所有的依赖 dependencies
,并且还要当做形参传到 factory
中,对于依赖的模块提前执行,依赖前置。
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
优点:
缺点:
在ES6之前,社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种(上面我们已经提到)。前者用于服务器,后者用于浏览器。ES6在语言规格的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。而CommonJS和AMD模块,都只能在运行时确定这些东西。比如,CommonJS模块就是对象,输入时必须查找对象属性。
为什么运行时确定依赖关系存在缺点呢?主要是不能够同时满足按需加载,请求合并和依赖管理这三个需求。
我们来看看ES6模块构建的基本过程吧:
大致来说,当 JS 引擎运行一个模块的时候,它的行为大致可归纳为以下四步:
1.解析:引擎实现会阅读模块的源码,并且检查是否有语法错误。
2.加载:引擎实现会(递归地)加载所有被引入的模块。
3.链接:引擎实现会为每个新加载的模块创建一个作用域,并且将模块中的声明绑定填入其中,包括从其他模块中引入的。
4.执行:终于,JS 引擎开始执行刚加载进来的模块中的代码。
好了,ES6模块化的思想我们已经阐述完了,那么具体的实现是怎样的呢?我们的webpack就是一个很好地实现了ES6模块化思想的工具啦。当然,webpack所做的比ES6模块化所涉及的要多得多。
在 Webpack 当中,最酷的一点就是将 Web 开发中常用的如 JavaScript、CSS 以及图片、字体等各种静态文件统称为模块,并对它们进行统一的模块化加载,预处理以及打包发布,从而让开发过程变得更为高效。而且,任何静态资源都可以视作模块,然后模块之间还可以相互依赖,通过 Webpack 对模块进行处理后,就可以打包成我们想要的静态资源。
就像前面所提到的那样,Webpack 具有和 RequireJS等模块化工具相类似的功能,但还有更多独有的新特性:
参考文档:
1.https://blog.jimmylv.info/2016-03-10-getting-webpack-done-and-js-module-history/
2.https://segmentfault.com/a/1190000003410285
3.http://webpack.github.io/docs/motivation.html