美文网首页
JS 模块化方案对比

JS 模块化方案对比

作者: 菜鸡前端 | 来源:发表于2021-09-17 17:16 被阅读0次

1. CommonJS 规范(同步加载 NodeJS)

// 导入
require("module");
require("../app.js");

// 导出
exports.getStoreInfo = function() {};
module.exports = someValue;

// 优点:使用上更简单,因为同步加载
// 缺点:在浏览器上,同步意味着阻塞加载,不能非阻塞的并行加载多个模块,客户端网络不可控
// 实现:NodeJS

2. AMD(异步加载模块 requireJS)

采用异步方式加载模块,模块的加载不影响后面语句的运行。所有依赖模块的语句,都定义在一个回调函数中,等到加载完成之后,回调函数才执行。

// 定义
define("module", ["dep1", "dep2"], function(d1, d2) {...});
                                                     
// 加载模块
require(["module", "../app"], function(module, app) {...});
  • 加载模块 require([module], callback);
    • 第一个参数[module],是一个数组,里面的成员就是要加载的模块;
    • 第二个参数callback是加载成功之后的回调函。
  • 优点:
    • 适合在浏览器环境中异步加载模块
    • 可以并行加载多个模块
  • 缺点:
    1. 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
    2. 不符合通用的模块化思维方式,是一种妥协的实现
  • RequireJS执行流程:
    1. require 函数检查依赖的模块,根据配置文件,获取js文件的实际路径
    2. 根据js文件实际路径,在dom中插入script节点,并绑定onload事件来获取该模块加载完成的通知。
    3. 依赖script全部加载完成后,调用回调函数

RequireJS 对模块的态度是预执行。由于 RequireJS 是执行的 AMD 规范, 因此所有的依赖模块都是先执行;即 RequireJS 是预先把依赖的模块执行,相当于把 require 提前了。

3. CMD规范(异步加载模块 SeaJS)

  • CMD规范和AMD很相似,一个模块就是一个文件。
  • 定义模块使用全局函数 define,其接收 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串;
  • factory 是一个函数,有三个参数,function(require, exports, module):
    1. require 是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口:require(id)
    2. exports 是一个对象,用来向外提供模块接口
    3. module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
define(function(require, exports, module) {
  var a = require('./a');
  a.doSomething();

  // 依赖就近书写,什么时候用到什么时候引入
  var b = require('./b');
  b.doSomething();
});
  • 优点:依赖就近,需要使用到模块时,显示的使用 require 来执行
  • 缺点:模块的加载逻辑偏重
  • 实现:SeaJS

4. AMD 与 CMD 的区别

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从2.0开始,也改成了可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
  2. AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require。
// AMD
define(['./a', './b'], function(a, b) {  // 依赖必须一开始就写好  
   a.doSomething()    
   // 此处略去 100 行    
   b.doSomething()    
   ...
});

// CMD
define(function(require, exports, module) {
   var a = require('./a')   
   a.doSomething()   
   // 此处略去 100 行   
   var b = require('./b') 
   // 依赖可以就近书写   
   b.doSomething()
   // ... 
});

5. UMD (统一模块规范)

  • UMD 是 AMD 和 CommonJS 的糅合
  • UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式;在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
(function (window, factory) {
    if (typeof exports === 'object') {
    
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
    
        define(factory);
    } else {
    
        window.eventUtil = factory();
    }
})(this, function () {
    //module ...
});

6. ESModule 规范

  • ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案;
  • ES6 模块设计原则:尽量的静态化、使得编译时就能确定模块的依赖关系;
// 导入
import "/app";
import React from “react”;
import { Component } from “react”;

// 导出
export function multiply() {...};
export var year = 2018;
export default ...
...
  • 优点:
    1. 容易进行静态分析
    2. 面向未来的 EcmaScript 标准
  • 缺点:
    1. 原生浏览器端还没有实现该标准

7. require(commonJS) 与 import(ESModule) 的区别

require使用与CommonJs规范,import使用于Es6模块规范;所以两者的区别实质是两种规范的区别;

7.1 CommonJS

  1. 对于基本数据类型,属于复制。即会被模块缓存;同时,在另一个模块可以对该模块输出的变量重新赋值。
  2. 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
  3. 当使用 require 命令加载某个模块时,就会运行整个模块的代码。
  4. 当使用 require 命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS 模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
  5. 循环加载时,属于加载时执行。即脚本代码在 require 的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。

7.2 ES6模块

  1. ES6模块中的值属于【动态只读引用】。
  2. 对于只读来说,即不允许修改引入变量的值,import 的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到 import 命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
  3. 对于动态来说,原始值发生变化,import 加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
  4. 循环加载时,ES6 模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。

8. ESModule 模块加载器的实现

使用 webpack 打包项目,会把 webpack 实现的模块加载器也打包进去,可以去看一下它的代码。

9. 在浏览器端尽量使用 ESModule

使用 ESModule 可以避免 tree-shaking 技术失效,因为它是静态分析的,如果使用 commonJS 会导致 tree-shaking 失效。

相关文章

  • JS 模块化方案对比

    1. CommonJS 规范(同步加载 NodeJS) 2. AMD(异步加载模块 requireJS) 采用异步...

  • 模块化开发

    什么是模块化? 模块化就是讲js文件按照功能分离,根据需求引入不同的文件中。源于服务器端。 js模块化方案有AMD...

  • 2021-07-19

    前言: 效果预览: 普通实现: 新增模块: 模块化实现: 新增模块: 方案对比: 总结:

  • Webpack原理-从前端模块化开始

    当前主流 JS 模块化方案 CommonJS 规范,nodejs 实现的规范 AMD 规范,requirejs 实...

  • (多人合作)怎么避免多人开发时函数重名的问题?

    解决方案1 基于单例模式实现模块化开发, 基于闭包实现模块化开发, 基于cmd, amd, common.js规范...

  • 聊聊前端模块化

    从JSP到React,前端模块化到底经历了哪些。 模块化方案 在ajax出现之前,js不需要实现复杂的业务需求,模...

  • 好程序员web前端教程分享js中的模块化一

    好程序员web前端教程分享js中的模块化一:我们知道最常见的模块化方案有CommonJS、AMD、CMD、ES6,...

  • 前端开发体系建设

    前端集成解决方案要求: 模块化开发。最好能像写nodejs一样写js,很舒服。css最好也能来个模块化管理! 性能...

  • 前端解决方案列表

    基于 Node.js 的前后端分离解决方案 基于 Webpack 的前端模块化解决方案 基于 JWT 的接口鉴权解...

  • 模块化开发

    js模块化开发vue模块化开发

网友评论

      本文标题:JS 模块化方案对比

      本文链接:https://www.haomeiwen.com/subject/lyhsgltx.html