本文的目的是为了能大让家更好的认识 Mod,之所以引入 RequireJS/SeaJS 的对比主要是应大家要求更清晰的对比应用场景,并不是为了比较出孰胜孰劣,RequireJS 和 SeaJS 都是模块化漫漫之路的先驱者,向他们致敬!

为工程化为生的Mod

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

JavaScript 并没有为开发者们提供以一种简洁、有条理地的方式来管理模块的方法。从出发点来看,Mod和 RequireJS/SeaJS 是一致的,为开发者提供一套 JavaScript 模块化开发方案,让 JavaScript 的模块化开发变得更简单自然。但是在实现的过程中却存在巨大着的差异。

Mod严格上来讲并不是一个独立的模块化框架,它是被设计用做前端工程化模块化方案的 JavaScript 支持,需要和自动化工具、后端框架配合来使用,目的在于希望给工程师提供一个类似 nodeJS 一样的开发体验,同时具备很好的线上性能。

RequireJS 和 SeaJS 的定位主要是 Web 浏览器端的模块加载器,依靠 JavaScript 运行时来支持模块定义、依赖分析和加载等功能。

类 CommonJS 的开发体验

RequireJS 遵守的是 AMD 规范,SeaJS 遵守的是 CMD 的规范。AMD/CMD 规范使用的是“异步模块定义”的方式,这种方式给开发带来了极大的不便,所有的同步代码都需要修改为异步的方式,我们是否可以在前端开发中使用“ CommonJS ”的方式,开发者可以使用自然、容易理解的模块定义和调用方式,不需要关注模块是否异步,不需要改变开发者的开发行为。答案当然是肯定的,Mod并不完全遵守 AMD/CMD 规范,也正是为了为开发者提供更简单自然的开发体验。

模块定义

Mod 使用 define 来定义一个模块:

define (id, factory)

factory 提供了 3 个参数:require, exports, module ,用于模块的引用和导出。

在平常开发中,我们无需关注模块定义,工具会自动对 JS 进行 define 包装处理:

JS 源码

//common/widget/menu/menu.js
var $ = require('common:widget/jquery/jquery.js'); exports.init = function() {
$('.menu-ui ul li a').click(function(event) {
var self = this;
$('.menu-ui ul li a.active').removeClass('active');
$(self).addClass('active');
event.preventDefault();
});
};

编译后代码

define('common:widget/menu/menu.js', function(require, exports, module){
var $ = require('common:widget/jquery/jquery.js');
exports.init = function() {
$('.menu-ui ul li a').click(function(event) {
var self = this;
$('.menu-ui ul li a.active').removeClass('active');
$(self).addClass('active');
event.preventDefault();
});
};
});

模块调用

Mod会在模块初始化之前自动加载相关依赖。因此当我们需要一个模块时,只需提供一个模块名即可获取:

require (id)

因为所需的模块都已预先加载,因此 require 可以立即(同步)返回该模块引用。无论在页面的 script 还是模块内部,工程师都可以放心通过 require 来加载模块,不需要考虑何时该使用同步接口何时调用异步接口。

避免模块化引来的性能问题

RequireJS/SeaJS 通过过 JavaScript 运行时来支持“匿名闭包”、“依赖分析”和“模块加载”等功能,“依赖分析”需要在 JavaScript 运行时通过正则匹配到模块的依赖关系,然后顺着依赖链(也就是顺着模块声明的依赖层层进入,直到没有依赖为止)把所有需要加载的模块按顺序一一加载完毕, 当模块很多、依赖关系复杂的情况下会严重影响页面性能。Mod通过以下设计避免了如上问题:

  • 通过工具自动添加 define 闭包,线上不需要支持匿名闭包
  • 通过工具自动处理依赖,线上不需要动态处理依赖
  • 通过后端模板自动插入 script,线上不需要通过前端框架进行模块加载

通过以上设计,Mod极其精简,整个文件只有 100 多行,相比下 RequireJS 有 2000 多行,SeaJS 有将近 1000 行。

避免模块化为打包部署带来的极大不便

通过 RequireJS/SeaJS 进行模块化开发后,合并静态资源(打包)将变得十分不方便和晦涩难懂,每个文件里只能有一个模块,无论是“ combo 插件”还是“ flush 插件”,都需要我们修改模块化调用的代码,这无疑是雪上加霜,工程师不仅需要在开发的时候关注模块定义,在调用的时候还需要关注在一个请求里面加载哪些模 块比较合适,模块化的初衷是为了提高开发效率、降低维护成本,但我们发现这样的模块化方案实际上并没有降低维护成本,某种程度上来说使得整个项目更加复杂 了。而使用 Mod,工程师只需要在配置文件配置合并策略即可,并不需要关注其他细节,Mod会自动处理好依赖以及合并信息并在模块初始化之前将模块的静态资源以及所依赖的模块加载并准备好。

自适应的性能优化

整个Mod模块化流程如下:

通过自动化工具对模块进行编译处理,包括对对 JavaScript 模块添加闭包、记录每个静态资源的部署路径以及依赖关系并生成资源表(resource map),如下所示,

{
"res": {
"demo.js": {
"uri": "/static/js/demo_33c5143.js",
"type": "js",
"deps": [
"demo.css"
],
"pkg": "p0"
},
"index.html": {
"uri": "/index.html",
"type": "html",
"deps": [
"demo.js",
"demo.css"
]
},
"script.js": {
"uri": "/static/js/script_32300bf.js",
"type": "js",
"pkg": "p0"
}
},
"pkg": {
"p0": {
"uri": "/static/pkg/aio_5bb04ef.js",
"type": "js",
"has": [
"demo.js",
"script.js"
],
"deps": [
"demo.css"
]
}
}
}

所有被打包的资源会有一个 pkg 属性 指向该表中的资源,而这个资源,正是我们配置的打包策略。有了这些信息,我们可以通过 Mod 框架(Mod 和后端框架)来管理和控制模块的加载。Mod的模块化可以十分灵活的适应各种性能优化场景,我们还可以通过监控模块的调用情况,自动生成最优的打包配置,让网站可以自适应优化。

总结

Mod提供的是一体化的模块化解决方案,更多的是从工程化、自动化的角度去考虑,RequireJS/SeaJS 更独立灵活。

参考:http://fex.baidu.com/blog/2014/04/fis-modjs-requirejs-seajs/?utm_source=tuicool&utm_medium=referral

http://www.tuicool.com/articles/yuY36n

Mod 与 RequireJS/SeaJS 的那些事的更多相关文章

  1. RequireJS 和 SeaJS

    RequireJS SeaJS CMD规范 CommonJS的规范: 根据CommonJS规范,一个单独的文件就是一个模块.加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的 ...

  2. 使用RequireJS并实现一个自己的模块加载器 (一)

    RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...

  3. requireJs,AMD,CMD

    知识点1:AMD/CMD/CommonJs是JS模块化开发的标准,目前对应的实现是RequireJs/SeaJs/nodeJs.   知识点2:CommonJs主要针对服务端,AMD/CMD主要针对浏 ...

  4. JavaScript AMD 模块加载器原理与实现

    关于前端模块化,玉伯在其博文 前端模块化开发的价值 中有论述,有兴趣的同学可以去阅读一下. 1. 模块加载器 模块加载器目前比较流行的有 Requirejs 和 Seajs.前者遵循 AMD规范,后者 ...

  5. Node.js这么下去...

    Node.js是基于javascript的.event驱动的单进程服务器(也能实现cluster模式,只要一个fork()语句,类似于C语言的进程创建). 所以大胆估计:Node.js会把很多大网站吞 ...

  6. 移动端 Web 开发前端知识整理

    文章来源: http://www.restran.net/2015/05/14/mobile-web-front-end-collections/ 最近整理的移动端 Web 开发前端知识,不定期更新. ...

  7. 网页插件学javascript还是jquery好啊?

    文章的起因,也是在群内交流是回答一个小伙的问题,一扯就停不下来,但由于个人知识面覆盖有限,自身基础又不够扎实,仅供参考: 问这个问题之前,我个人建议先搞清什么是jquery,什么是js?     jq ...

  8. grunt 入门学习

    前端工作流,Grunt上手指南 Posted@2013-04-20 7:15 a.m. CategoriesGrunt ,  javascript 我想先花点时间回忆一下作为一个前端需要做的工作(Lo ...

  9. JavaScript内存优化

    JavaScript内存优化 相对C/C++ 而言,我们所用的JavaScript 在内存这一方面的处理已经让我们在开发中更注重业务逻辑的编写.但是随着业务的不断复杂化,单页面应用.移动HTML5 应 ...

随机推荐

  1. [Java] 模拟HTTP的Get和Post请求

    在之前,写了篇Java模拟HTTP的Get和Post请求的文章,这篇文章起源与和一个朋友砍飞信诈骗网站的问题,于是动用了Apache的comments-net包,也实现了get和post的http请求 ...

  2. 【阿里云产品公测】阿里云OpenSearch初次使用评测

    作者:阿里云用户 bailimei 从一开始我就对opensearch非常陌生,这是我第一次接触它,本以为对我来说上手难度会比较大,看完帮助信息后我决定试用看看,经试用后我发现阿里云opensearc ...

  3. 【Linux/Ubuntu学习8】unbuntu 下播放swf文件

    ubuntu是没有自带swf播放器的,需要自己安装. 这次介绍的这个播放器是gnome环境的. 安装: sudo apt-get install swfdec-gnome

  4. Android小项目之十一 应用程序的主界面

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...

  5. iOS平常注意1

    在写oc代码时的注意有一些错误看看各位朋友在平常注意了编写是的小错误我也会不断总结的 1. [NSTimer scheduledTimerWithTimeInterval:1 target:self ...

  6. The requested URL Not Found问题

    遇到这么一个问题: 最近刚转到linux下工作 在本地运行localhost下的thinkphp程序时,出现 一开始以为是权限问题,把目录以及文件权限都改为777依然不起作用 后来发现是rewrite ...

  7. Unhandled Error in Silverlight Application “Syncfusion.Silverlight.Olap.Gauge.OlapGauge”的类型初始值设定项引发异常

    Silverlight 在运行时,如果出现如下错误: 检查生成的xap文件,解压出来,看是否里面包含该DLL:Syncfusion.Silverlight.Olap.Gauge.OlapGauge

  8. AI-->从新建文档开始说起,串联相关色彩知识

    相关概念:AI.PS.矢量图形 AI:  Adobe Illustrator 是Adobe公司出品的一款用于矢量图形设计的软件. 矢量图形:用通俗的大白话讲与分辨率无关,可以任意的放大缩小而不会失真图 ...

  9. 【转】PS学堂之一:展示一下自己做的圆形印章

    共分七个步骤: 1.点击文件--新建,新建一个500×500像素,背景为透明的文件,选择RGB颜色. 2.把前景色和文字颜色设置为正红(R为255,G和B为0). 3.在视图下拉菜单中选择标尺,将横. ...

  10. 百度编辑器ueditor前台代码高亮无法自动换行解决方法

    这两天本站成功安装整合了百度编辑器ueditor,用着还挺不错,但是遇到了点小问题 问题描述:   在内容里面插入代码高亮显示,后台编辑器中是可以自动换行的,但是发表后,在前台查看,发现代码不能自动换 ...