js的模块方案:CommonJS、AMD和CMD

什么是CommonJS、AMD和CMD

CommonJS、AMD和CMD都是js的模块加载方案,JS在最初设计的时候,并没有模块这种概念,也没有提供将各模块进行灵活组装的机制,有的同学说,<script>标签不就可以吗?<script>是可以帮我们把代码组装起来,但是功能太薄弱,而且因为是标签,所以只能在浏览器里面用,对于我们的nodejs就无能为力了,所以算不上模块解决方案。

后来nodejs出现之后,js可以横跨前后两端进行开发,模块成了不得不解决的一个问题,一些技术爱好者组成了技术社区,社区的推动下,制定了CommonJS模块的规范,nodejs依照此规范,实现了自己的模块加载机制。

CommonJs有啥特点

在CommonJS中,有一个全局性方法require(),用于加载模块。比如我们想要操作文件,就需要fs模块:

const fs = require('fs')
fs.readFile('a.txt', 'utf8', function(err, data) {
  console.log(data)
})

CommonJS是在运行时加载模块的,因为CommonJS认为模块就是对象:

// CommonJS模块
const { stat, exists, readFile } = require('fs');

// 等同于
const _fs = require('fs');
const stat = _fs.stat;
const exists = _fs.exists;
const readfile = _fs.readfile;

上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”,比如语法分析和类型检验,这是CommonJS的一大不足。

CommonJS的另外一个不足是模块的加载都是同步的,也就是说:

const fs = require('fs')

console.log('hello world')

只有等到fs模块加载完成之后,后面的代码才有机会执行,哪怕后面并没有用到fs模块。

这在服务器端没什么问题,但是在浏览器上却行不通,因为浏览器加载模块的时候,需要通过网络,如果网络出现异常,模块加载卡住,后面的代码就得不到运行,浏览器也会陷入假死状态,我们希望当模块加载失败的时候,一些跟该模块无关的代码依然可以运行,这就需要一种新的模块加载机制——AMD。

什么是AMD

AMD也是搞CommonJs的那帮人搞出来的,据说这帮人搞出来的CommonJs在nodejs上效果显著,于是雄心勃勃的向浏览器挺近,但是在内部遇到了很大的分歧,最后形成了三个流派,其中一个流派就推出了AMD规范,AMD的全称是“Asynchronous Module Definition”,即“异步模块定义”,从名字上可以看出,它加载模块的方式是异步的,AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:

require(['fs'], function(fs) {
  // to do something
})

console.log('hello world')

这样模块fs的加载,就不会影响console.log的执行,程序相对来说更坚挺。

AMD有个缺陷,来看下面这段代码:

const env = 'dev'
require(['fs', 'path'], function(fs, path) {
  if (env === 'dev') {
    fs.unlink('./a.txt', err => console.log('文件删除成功!'))
  }

  if (env === 'test') {
    console.log(path.sep)
  }
})

console.log('hello world')

可以看出,虽然代码加载了fspath两个模块,但是在程序正真执行的过程中,有些模块的加载其实是没有必要的,即使加载了,在之后的回调中也没有被用到,这样在一定程度上造成了浪费。

如何解决AMD的缺陷

为了解决这个问题,阿里巴巴的一个叫玉伯的前端开发,提出了CMD规范(Common Module Definition),并根据此规范,写了一个专门的模块加载器——sea.js,sea在英文中是大海的意思,这也表达了作者对这个加载器的态度——海纳百川,有容乃大。

与sea起名的是AMD下的一个加载器,叫RequireJS

sea在加载模块时也是异步的,它主要的特点是允许你在使用模块的时候才去加载模块:

const env = 'dev'

define(function(require, exports, module) {
  if (env === 'dev') {
    const fs = require('fs')
    fs.unlink('./a.txt', err => console.log('文件删除成功!'))
  }

  if (env === 'test') {
    const path = require('path')
    console.log(path.sep)
  }
})

console.log('hello world')

编写模块要注意什么

我们在设计模块的时候,需要尽可能的做到高内聚,低耦合。

高内聚实际上就是要求我们在开发的时候,遵守单一职责原则,也就是一个模块,里面的各个功能元素(类或者函数)应该只做好自己的本职工作,千万不要当老好人,什么都想搭把手。一个旅游团,导游负责景点讲解,司机负责开车,游客负责卖萌拍照,每个人各司其职,旅游就能有条不紊的进行下去,但是,如果游客想帮司机开车,司机也想替游客讲两个景点故事,虽然是好心,但是容易办坏事。

低耦合主要是之模块与模块之间的关系尽可能的简单,如果一个模块需要修改,应该尽可能的不会影响到其他模块,避免发生牵一发而动全身的情况,这样本身也能极大的节约我们的时间。

模块的价值是什么

模块最大的价值是规范和封装了代码,提高了代码的复用性,只要遵守模块的规则,写出来的模块就可以被各个系统使用,提高代码的流动性,可以说,模块是代码世界的集装箱,通过将代码封装成模块,可以很方便的运输到各个行业的各个系统中运行,从而极大的放大了代码的价值。

其中,github模块的仓库,是伟大码农的智慧的结晶,也是世界上(可能)最大的基友交友平台。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容