Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端模块化 #20

Open
XJIANBIN opened this issue Jun 18, 2019 · 0 comments
Open

前端模块化 #20

XJIANBIN opened this issue Jun 18, 2019 · 0 comments

Comments

@XJIANBIN
Copy link
Owner

模块化开发的价值

1 避免命名冲突
当新增一个函数
(1)在原来的函数上面去增加功能,这样就违背了工具函数单一性原则,并且还得理解原函数的的逻辑
(2)新增一个函数,这样子就需要人工全局检查名字冲突,如果项目比较大效率就很难保证。
2 便于依赖管理
浏览器按照从上往下加载,如果存在两个相邻的 script 标签,就先加载并执行第一个之后再解析下一个,所以在模块化出现之前,处理依赖加载的方式都是通过控制标签顺序来实现。这样随着项目复杂度的提升,维护难度不断提高。通过模块化的规范解决错综复杂的依赖管理问题,降低开发难度和维护难度,让开发者将更多的经历投入到业务逻辑中。
3 利于性能优化
(1)通过模块化规范的依赖管理让按需加载的模块更易于管理
(2)使用模块化构建工具将模块进行打包,可以减少客户端的请求,提高 web 的解析速度
4 提高可维护性
5 利于代码复用

模块化开发

无模块时代

1 全局变量灾难
2 函数命名冲突
3 依赖关系不好处理

模块化面临问题

1 如何安全的包装一个模块的代码?(不污染模块外的任何代码)
2 如何唯一标识一个模块?
3 如何优雅的把模块的 API 暴漏出去?(不能增加全局变量)
4 如何方便的使用所依赖的模块

发展历史

1 一开始是在服务端的 CommonJS ,它定义了全局函数 require,通过传入模块标识来引入其他模块,如果被引入的模块又依赖了其他模块,
那么会依次加载这些模块;
通过 module.exports 向外部暴露 API,以便其他的模块引入。由于 CommonJS 加载模块是同步的,即只有加载完成才能进行接下来的操作,在服务器端,文件都是保存在硬盘上,
所以同步加载没有问题,但是对于浏览器端,需要将文件从服务器端请求过来,那么同步加载就不适用了,所以,CommonJS 是不适用于浏览器端的。因此当应用于浏览器端时会受到网速的限制。
2 之后出现了 AMD 和 CMD 浏览器端的模块开发规范,可以实现异步模块加载。
分别对应 requirejs 和 seajs
AMD 推崇依赖前置,提前执行,CMD`推崇就近依赖,延迟执行。
两种都是提前下载

UMD: 通用模块规范
既然CommonJs和AMD风格一样流行,似乎缺少一个统一的规范。所以人们产生了这样的需求,希望有支持两种风格的“通用”模式,于是通用模块规范(UMD)诞生了。
这个模式略难看,但是它兼容了AMD和CommonJS,同时还支持老式的“全局”变量规范:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS之类的
        module.exports = factory(require('jquery'));
    } else {
        // 浏览器全局变量(root 即 window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    //    方法
    function myFunc(){};

    //    暴露公共方法
    return myFunc;
}));

3 ES6 中给出了 import export 这样的方案,目前为止我们都是通过 babel 将 ES6 代码转为 ES5,import 转为了
require,export 转为了 module.exports,即 commonJS。

requirejs 导入模块的方式实际就是创建脚本标签,并且监听 onload 事件

资料 1
JavaScript 模块的循环加载

commonjs 加载原理

CommonJS 的一个模块,就是一个脚本文件。require 命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象。

{
  id: '...',
  exports: { ... },
  loaded: true,
  ...
}

以后需要用到这个模块的时候,就会到 exports 属性上面取值。即使再次执行 require 命令,也不会再次执行该模块,而是到缓存之中取值。

COMMONJS 服务端开发的规范

(1)是 javascript 的静态模块化规范,只适用于服务端 nodejs 开发 ,因为在它是同步加载模块的,这在浏览器端时会受到网速的限制。
(2)模块均是同步阻塞式加载,无法实现按需异步加载。

AMD(异步模块定义) 规范 浏览器端模块化开发的规范

define(id?, dependencies?, factory);

    1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
    1. CMD 推崇依赖就近,AMD 推崇依赖前置。

无论是 commonjs 还是 amd 和 cmd ,三者都是折中的产物,缺点:
(1)应用场景单一,无法跨环境使用
(2)构建工具不统一
(3)不同规范模块无法混合使用

ES6 MOdule

目前 stage3 阶段的 import()函数可以满足按需加载需求,babel 和 webpack 已经实现对此函数的支持。

ES 模块加载原理

深入理解 ES Modules

commonjs 和 es6 对循环加载的处理方式

JavaScript 模块的循环加载
1 CommonJS 的做法是,一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
2 ES6 模块的运行机制与 CommonJS 不一样,它遇到模块加载命令 import 时,不会去执行模块,而是只生成一个引用。等到真的需要用到时,
再到模块里面去取值。

模块化和组件化

模块化中的模块一般指的是 Javascript 模块,将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。
块的内部数据相对而言是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。比如一个用来格式化时间的模块。
组件化将模板、样式和逻辑都抽象独立出来,是一个独立的可视和可交互的单元,组件则包含了 template、style 和 script,而它的 Script
可以由各种模块组成。

模块化

模块化方案看法

模块化是一种处理复杂系统的方式,它可以把系统代码划分为一系列职责单一,高度解耦合且可替换的模块,使系统的可维护性更加简单易得。

COMMONJs 的诞生开启了“ JavaScript 模块化的时代”,CommonJS 的模块提案为在服务器端的 JavaScript 模块化做出了很大的贡献,
但是在浏览器下的 JavaScript 模块应用很有限。随之而来又诞生了其它前端领域的模块化方案,像 requireJS、SeaJS 等,然而这些模块化方案
并不是十分适用 ,并没有从根本上解决模块化的问题。

ES6 模块的循环加载,如果存在着相互调用,且存在截止条件,并不会是程序崩溃。但是,如果造成了无限循环调用,会使得程序崩溃,内存溢出。
ES6 模块,使用 import 引入时,其实是建立了与模块之间的引用,当用到引入的模块中的变量时,再去模块里取值。

模块导出的方法

es5 exports module.exports
es6 export
export default 默认输出的一个变量

module.exports, exports 是对象,而 export, export defalut 是 ES6 的语法

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant