|
| 1 | +--- |
| 2 | +title: js模块化 |
| 3 | +published: 2025-02-11 |
| 4 | +category: 技术人生 |
| 5 | +tags: ["js"] |
| 6 | +image: js.png |
| 7 | +--- |
| 8 | + |
| 9 | +# js 模块化 |
| 10 | + |
| 11 | +## 什么是模块化 |
| 12 | + |
| 13 | +首先可以通过黄玄的博客了解一下模块化的发展历程。 |
| 14 | +[JavaScript 模块化七日谈 - 黄玄的博客 | Hux Blog](https://huangxuan.me/2015/07/09/js-module-7day/) |
| 15 | + |
| 16 | +## 模块化的标准 |
| 17 | + |
| 18 | +Commonjs: |
| 19 | +Nodejs 是 commonjs 规范的主要实践者。 |
| 20 | +实际使用时用 **Module.exports**定义当前模块对外输出的接口,用 require 加载模块. |
| 21 | +Common js 用同步的方式加载模块。在服务器端由于时硬盘架在,读取速度很快,所以不存在什么问题,如果是在浏览器端,受制于网络环境的影响,会导致页面卡顿假死的现象,更合理的方式就是使用异步加载的方式。 |
| 22 | + |
| 23 | +**amd 和 requirejs** |
| 24 | + |
| 25 | +Amd(Asynchronous Module Definition)规范采用的是异步加载模块的方式,模块的加载不会影响后面语句的执行, 所有依赖于模块的语句都写在回调函数中,只有当模块全部加载完毕才会执行后面的回调函数。 |
| 26 | +Amd 是一种规范,异步加载模块的一种思想,而 requirejs 是 amd 规范的一种应用。 |
| 27 | + |
| 28 | +requirejs 的基本使用[Javascript 模块化编程(三):require.js 的用法 - 阮一峰的网络日志](https://www.ruanyifeng.com/blog/2012/11/require_js.html) |
| 29 | + |
| 30 | +其大概思想就是: |
| 31 | +引入 requirejs 文件,设置为异步加载,在标签中属性声明网页程序的主模块。 |
| 32 | +在主模块中声明要引入的基础模块。 |
| 33 | +使用 requeire.config()指定引用路径,define()定义模块,require()加载模块。 |
| 34 | + |
| 35 | +```javascript |
| 36 | +/** 网页中引入require.js及main.js **/ |
| 37 | +<script src="js/require.js" data-main="js/main"></script>; |
| 38 | + |
| 39 | +/** main.js 入口文件/主模块 **/ |
| 40 | +// 首先用config()指定各模块路径和引用名 |
| 41 | +require.config({ |
| 42 | + baseUrl: "js/lib", |
| 43 | + paths: { |
| 44 | + jquery: "jquery.min", //实际路径为js/lib/jquery.min.js |
| 45 | + underscore: "underscore.min", |
| 46 | + }, |
| 47 | +}); |
| 48 | +// 执行基本操作 |
| 49 | +require(["jquery", "underscore"], function ($, _) { |
| 50 | + // some code here |
| 51 | +}); |
| 52 | +``` |
| 53 | + |
| 54 | +```javascript |
| 55 | +// 定义math.js模块 |
| 56 | +define(function () { |
| 57 | + var basicNum = 0; |
| 58 | + var add = function (x, y) { |
| 59 | + return x + y; |
| 60 | + }; |
| 61 | + return { |
| 62 | + add: add, |
| 63 | + basicNum: basicNum, |
| 64 | + }; |
| 65 | +}); |
| 66 | +// 定义一个依赖underscore.js的模块 |
| 67 | +define(["underscore"], function (_) { |
| 68 | + var classify = function (list) { |
| 69 | + _.countBy(list, function (num) { |
| 70 | + return num > 30 ? "old" : "young"; |
| 71 | + }); |
| 72 | + }; |
| 73 | + return { |
| 74 | + classify: classify, |
| 75 | + }; |
| 76 | +}); |
| 77 | + |
| 78 | +// 引用模块,将模块放在[]内 |
| 79 | +require(["jquery", "math"], function ($, math) { |
| 80 | + var sum = math.add(10, 20); |
| 81 | + $("#sum").html(sum); |
| 82 | +}); |
| 83 | +``` |
| 84 | + |
| 85 | +## cmd 和 seajs |
| 86 | + |
| 87 | +Cmd(Common Module Definition)模块加载规范。 |
| 88 | +Cmd 和 amd 规范差不多,但是 cmd 提倡的是依赖就近,延迟执行。而 amd 提倡的是依赖提前,提前执行。 |
| 89 | +Seajs 就是实现 cmd 规范的一个应用。 |
| 90 | + |
| 91 | +```javascript |
| 92 | +/** AMD写法 **/ |
| 93 | +define(["a", "b", "c", "d", "e", "f"], function (a, b, c, d, e, f) { |
| 94 | + // 等于在最前面声明并初始化了要用到的所有模块 |
| 95 | + a.doSomething(); |
| 96 | + if (false) { |
| 97 | + // 即便没用到某个模块 b,但 b 还是提前执行了 |
| 98 | + b.doSomething(); |
| 99 | + } |
| 100 | +}); |
| 101 | + |
| 102 | +/** CMD写法 **/ |
| 103 | +define(function (require, exports, module) { |
| 104 | + var a = require("./a"); //在需要时申明 |
| 105 | + a.doSomething(); |
| 106 | + if (false) { |
| 107 | + var b = require("./b"); |
| 108 | + b.doSomething(); |
| 109 | + } |
| 110 | +}); |
| 111 | + |
| 112 | +/** sea.js **/ |
| 113 | +// 定义模块 math.js |
| 114 | +define(function (require, exports, module) { |
| 115 | + var $ = require("jquery.js"); |
| 116 | + var add = function (a, b) { |
| 117 | + return a + b; |
| 118 | + }; |
| 119 | + exports.add = add; |
| 120 | +}); |
| 121 | +// 加载模块 |
| 122 | +seajs.use(["math.js"], function (math) { |
| 123 | + var sum = math.add(1 + 2); |
| 124 | +}); |
| 125 | +``` |
| 126 | + |
| 127 | +ES6 module |
| 128 | +Js 从语言层面上规定了模块化的标准,旨在通过标准来实现浏览器和服务器环境上模块化的统一解决方案。 |
| 129 | + |
| 130 | +Es6 加载模块是在编译时就加载好的,而不是运行时,所以无法时间条件加载。正因为如此,才使得静态分析成为可能。 |
| 131 | + |
| 132 | +ES6 模块和 common js 的三大差异 |
| 133 | + |
| 134 | +1. common JS 模块的输出的是一个值的拷贝,es 6 模块的输出是值的引用。 |
| 135 | +2. common js 模块是运行时加载, es6 模块是编译时输出接口。 |
| 136 | +3. Common js 模块的 require()是同步加载模块,es6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段。 |
| 137 | + |
| 138 | +Es6 的模块导出类似于 unix 中 符号连接。软链接。 |
| 139 | + |
| 140 | +原生 js 组织阶段 - 在线处理阶段 - 预处理阶段 |
| 141 | + |
| 142 | +1. 原生阶段使用原生的 js 去组织模块 |
| 143 | +2. 在线处理使用的 amd 或者 cmd 或者 es6+babel 这种去处理模块间的依赖,最终是在浏览器去处理依赖关系。 |
| 144 | +3. 预处理阶段使用 broswerify 或者 webpack 这种预处理工具将模块之间打包成单个或者几个问题,压缩首次访问页面 http 的请求数量,提高性能。 |
| 145 | + |
| 146 | +预处理阶段会碰到的问题是如果处理单个文件过大的问题。 |
| 147 | +可以通过代码拆分的插件来阶段将实现两个大的功能点: |
| 148 | + |
| 149 | +1. 实现第三方库和业务代码的分离。 |
| 150 | +2. 实现按需加载 |
0 commit comments