遇到的问题
来看示例:
// math.js
Math = {};
Math.add = function(n, m) { return n + m; };
// increment.js
function increment(val) { return Math.add(val, 1); }
// program.js
alert(increment(1));
假设 math.js 是数学静态方法库,increment.js 是具体业务代码,program.js 是执行入口。在 html 页面,最直接的引入方式:
<script src="math.js"></script>
<script src="increment.js"></script>
<script src="program.js"></script>
在真实场景下,上面的方式有以下问题:
- js 文件的下载是串行和阻塞的。
- 全局空间污染,暴露了 Math, increment 全局变量。在真实场景下,有可能会更多。
- js 文件的引入顺序不能调换,开发者必须知道文件之间的依赖关系。
- HTTP 链接数过多。
针对上面的问题,典型的解决方法有:
- 用 script injection 的方式并行异步下载文件,比如 LabJS, HeadJS, ControlJS 等 script loaders.
- 模拟 namespace 来减少全局污染,比如上面的示例代码可放入
X.Math, X.Biz
等命名空间。 - 采用一定的机制,将 script 的文件下载和模块代码的执行分开,自动管理依赖信息,比如 YUI3 的
YUI.add
和YUI.use
- 采用 Ant 等打包工具,或 cdn combo 服务,按需合并文件,减少 HTTP 链接数。
YUI3 的解决方案
我们重点分析 YUI3 的解决方案:
// math.js
YUI.add('math', function(Y) {
Y.Math = {};
Y.Math.add = function(n, m) { return n + m; };
});
// increment.js
YUI.add('increment', function(Y) {
var Math = Y.Math;
Y.increment = function (val) { return Math.add(val, 1); }
}, '1.0', { requires: ['math'] });
// program.js
YUI.add('program', function(Y) {
alert(Y.increment(1));
}, '1.0', { requires: ['increment'] });
页面中的引入方式如下:
<script src="yui-min.js"></script>
<script>
YUI({
modules: {
'math': {
fullpath: 'math.js'
},
'increment': {
fullpath: 'increment.js',
requires: ['math']
},
'program': {
fullpath: 'program.js',
requires: ['increment']
}
}
}).use('program');
</script>
online demo: math/yui3/test.html
YUI3 的解决方案已经很不错,但以下几点依旧有改进空间:
- use 多个 js 文件时,无论是否有依赖关系,下载都是串行的。注:可以通过配置 base 和 combine 来开启 combo 合并下载。对于内置模块来说,这样做效果不错。但对于非内置模块,需要有类 YAHOO! CDN combo 服务,不是很方便。另外,也并不是所有模块都需要 combo 起来下载。更推荐的做法是,根据访问频率和更新频率等信息,计算出缓存利用率,以此来决定最佳打包策略。
- 无论是内置模块还是外部模块,use 前都需要预先添加好配置信息。内部模块的巨大配置文件:yui3.js, 修改了模块的依赖关系时,还得维护该文件,不够方便。外部模块的配置信息,就是示例
YUI({modules:{...}})
中的代码,也比较恼人。
进一步考虑普适性和 DRY 原则,还可以分析出以下不足:
- 信息冗余。math.js 文件名已经表明了该文件是 math 模块,但 YUI.add 里,还得显式指明模块名称。示例代码中的依赖信息也有冗余。
- 种子过大。yui-min.js + loader-min.js, gzip 前 53.3k, gzip 后依旧有 18k. 对于 seed 来说,这个大小是不能用“小巧”来形容的,特别是在国内网速下。
- add 的功能是纯注册;use 的功能,不仅包括下载,还管理了模块 factory 的执行,这有悖职责单一原则,不能延迟执行。
- 所有模块都依附到 Y 实例上。有部分模块的模块名和 Y 上命名空间不对应,比如
YUI().use('dd-drop', function(Y) { /*Y.DD*/ })
, 这种不对应会加重使用者的记忆负担,不够直观。 - YUI3 的模块,仅能用于 YUI3, 普适性不是很好。
总之,在模块加载上,YUI3 很重,不光文件重,配置也重。在 CommonJS 时代,我们或许有更好的选择。
SeaJS 的尝试
SeaJS 的灵感来自 CommonJS 规范。Modules/2.0 规范目前还在讨论中:CommonJS Moules/2.0. SeaJS 遵循了规范里的大部分规定。其核心理念有:
- 职责单一原则:模块的声明、下载和执行是三个不同的步骤,在 API 的设计和实现上,应当尽量分离。
- 约定优于配置:模块所在路径和文件名,就是模块的标识,无需另行指定。这也是 DRY 原则的体现。
- 懒懒原则:能不执行的就先不执行,确实需要时才执行。
在 CommonJS Modules/2.0 里,我们这样写代码:
// math.js
module.declare([], function(require, exports) {
exports.add = function(n, m) {
return n + m;
};
});
// increment.js
module.declare(['math'], function(require, exports) {
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
}
});
// program.js
module.declare(['increment'], function(require) {
var inc = require('increment').increment;
alert(inc(1));
});
html 页面里的写法也很简单:
<script src="module.js"></script>
<script>
module.provide(['increment'], function(require) {
var inc = require('increment').increment;
alert(inc(1));
});
</script>
或者更简明的写成:
<script src="module.js" data-main="program"></script>
online demo: math/seajs/test.html
上面的示例,已经将 SeaJS Module Loader 的 API 都演示完了:
- 声明模块:
module.declare(id?, deps, factory)
- 提供模块:
module.provide(ids, callback)
- 获取模块:在 factory 里调用
require(id)
表面上看起来, 和 YUI3 很类似。但从设计上分析,存在质的区别:
- YUI3 的模块信息基于配置,SeaJS 则基于约定;
- YUI3 将模块都依附到 Y 上,依旧存在命名空间;SeaJS 的设计里,通过
var xx = require('xx-id')
来获取,彻底脱离了对命名空间的依赖; - exports 的设计,使得模块接口的暴露和模块之间的协作简单可靠;
- YUI3 的模块只能用于 YUI 类库,SeaJS 的模块可以用于 NodeJS, CouchDB 等环境下,更具有普适性。
从实现上看,SeaJS 还有以下优点:
- 代码非常小巧,目前 gzip 前 3.3k, gzip 后只有 1.7k.
- 非依赖项的模块文件是并行下载的;
- 模块代码,在第一次
require(id)
时才执行,这能节省初始 cpu 消耗,甚至整体消耗; - 还有 data-main 等设置,使得页面里,只需引入 seajs/module.js 即可;
- 还有循环依赖的处理、相对路径的支持等等,遵循了 CommonJS 规范,普适性和灵活性上都很好。
更多功能可以看测试用例:Test Suite for module.js
目前 SeaJS 还在开发中,对于 packages 的支持、模块版本、时间戳、子模块等等,依旧还存在设计和摸索中,如果你有兴趣,非常欢迎 fork 以下代码:
相关推荐
SeaJS 是一个专门为 JavaScript 设计的模块加载框架,它的出现是为了应对 JavaScript 在大型项目中代码组织和管理的挑战。在 JavaScript 开发中,模块化是一个关键的实践,它有助于提高代码的可读性、可维护性和复用...
SeaJS 是一款强大的JavaScript模块加载框架,其设计目标是遵循CommonJS规范,为开发者提供一个在浏览器环境中组织和管理代码的高效工具。CommonJS规范旨在促进JavaScript模块化,使得代码可复用性和可维护性得到显著...
Seajs是一款轻量级的JavaScript模块加载器,它遵循CommonJS规范,旨在解决浏览器环境中的模块化问题。在深入理解seajs源代码之前,我们首先需要了解模块化的基本概念和CommonJS规范。 模块化是软件开发中的一种组织...
SeaJS是中国开源社区贡献的一款JavaScript模块加载框架,其主要目标是为Web开发提供一种遵循CommonJS规范的模块化解决方案。这个框架的版本v0.9.1是一个免费版,适用于各种项目开发,帮助开发者更有效地组织和管理...
SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。
2. **CMD(Common Module Definition)规范**:Seajs 遵循 CMD 规范,它强调的是异步加载模块,这使得页面能够按需加载,提高页面性能。CMD 规范的两个核心概念是 `require` 和 `exports`,用于模块的引入和导出。 ...
Seajs是中国开源社区非常受欢迎的一款JavaScript模块加载器,它的出现为Web开发引入了CommonJS规范,使得前端开发更加模块化,便于代码管理和维护。Seajs 2.3.0是该库的一个稳定版本,提供了丰富的功能和优化。 一...
**SeaJS 和 RequireJS 是两种广泛使用的 JavaScript 模块加载器和依赖管理工具,它们的主要目的是解决 JavaScript 在浏览器端的异步加载和模块化问题。** **SeaJS** SeaJS 是一个轻量级的模块加载器,由中国淘宝...
SeaJS 是一款专为Web端设计的JavaScript模块加载器,它的出现是为了解决JavaScript在浏览器环境中的组织和管理问题。随着Web应用的复杂度不断提升,JavaScript代码的组织和依赖管理变得至关重要,SeaJS 提供了一种...
Seajs是早期广泛使用的CMD(Common Module Definition)规范的实现,而ES Modules则是现代浏览器和Node.js原生支持的模块系统。本文将详细介绍如何通过脚本将Seajs模块转换为ES Modules,并探讨这两种模块系统的差异...
SeaJS 是一个遵循 CommonJS 规范的模块加载框架,可用来轻松愉悦地加载任意 JavaScript 模块
1. **模块加载策略**:Seajs采用`CMD (Common Module Definition)`模式,即命令式模块定义。模块的加载和执行是异步的,只有当模块被实际引用时才会加载,这提高了页面的加载效率。 2. **模块标识**:模块可以通过...
SeaJS 是一款强大的 JavaScript 模块加载框架,其设计灵感来源于 CommonJS 规范,旨在为前端开发者提供一种模块化开发的方式,使 JavaScript 代码更加结构化、易于管理和复用。SeaJS 的核心目标是让在浏览器环境中...
SeaJS 是一个轻量级的前端模块加载器,它的出现是为了改善JavaScript在浏览器环境中的组织和加载方式。本文将深入探讨SeaJS的基本概念、工作原理以及如何通过一个完整的例子来理解其用法。 SeaJS的核心理念是遵循 ...
Seajs是中国开源社区发展出来的一款轻量级的前端模块化加载器,它的出现是为了应对JavaScript在浏览器端组织和管理代码的复杂性。本手册将详细阐述Seajs的核心概念、使用方法以及如何通过它来构建高效的前端应用。 ...
1. **模块化管理**:Seajs实现了CMD(Common Module Definition)规范,允许开发者在浏览器端定义、加载和使用模块。CMD与服务器端的CommonJS类似,但延迟执行和异步加载是其显著特点,适合浏览器环境。 2. **模块...
Seajs 是一个轻量级的前端模块加载器,它的出现是为了在浏览器端实现 CommonJS 规范,使得 JavaScript 的组织和开发变得更加模块化。Seajs 版本 2.3.0 是其稳定的一个版本,提供了更完善的特性和优化。 在...
在上面提到的场景下,其实seajs仅仅需要处理模块管理,对于大部分代码完成的模块加载其实是不需要的,如果在这时使用Seaport替代seajs,会大幅减少基础文件的请求体积。对于患有轻度代码洁癖的患者来说这可是一剂...
Seajs是中国开源社区推出的一款基于模块化开发的前端加载器,它借鉴了CommonJS的模块化思想,但针对浏览器环境进行了优化。Seajs的核心理念是让JavaScript模块化变得简单,帮助开发者解决在大型Web项目中代码组织、...
Seajs是中国著名的前端模块加载器,它借鉴了CommonJS的规范,使得JavaScript在浏览器环境中也能实现模块化的开发。这个“seajs-2.1.1.rar”压缩包包含的是Seajs的2.1.1版本,这是一个稳定且广泛使用的版本。下面我们...