`
mr.a
  • 浏览: 95154 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

打造最出色的模块加载框架:SeaJS Module Loader v0.3.0 预览版

    博客分类:
  • js
阅读更多

 

转自 

http://www.uini.net/2011/01/load-modules-to-create-the-best-framework-seajs-module-loader-v0-3-0-preview.html

 

打造最出色的模块加载框架:SeaJS Module Loader v0.3.0 预览版

遇到的问题

来看示例:

// 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>

在真实场景下,上面的方式有以下问题:

  1. js 文件的下载是串行和阻塞的。
  2. 全局空间污染,暴露了 Math, increment 全局变量。在真实场景下,有可能会更多。
  3. js 文件的引入顺序不能调换,开发者必须知道文件之间的依赖关系。
  4. HTTP 链接数过多。

针对上面的问题,典型的解决方法有:

  1. 用 script injection 的方式并行异步下载文件,比如 LabJS, HeadJS, ControlJS 等 script loaders.
  2. 模拟 namespace 来减少全局污染,比如上面的示例代码可放入 X.Math, X.Biz 等命名空间。
  3. 采用一定的机制,将 script 的文件下载和模块代码的执行分开,自动管理依赖信息,比如 YUI3 的 YUI.add和 YUI.use
  4. 采用 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 的解决方案已经很不错,但以下几点依旧有改进空间:

  1. use 多个 js 文件时,无论是否有依赖关系,下载都是串行的。注:可以通过配置 base 和 combine 来开启 combo 合并下载。对于内置模块来说,这样做效果不错。但对于非内置模块,需要有类 YAHOO! CDN combo 服务,不是很方便。另外,也并不是所有模块都需要 combo 起来下载。更推荐的做法是,根据访问频率和更新频率等信息,计算出缓存利用率,以此来决定最佳打包策略。
  2. 无论是内置模块还是外部模块,use 前都需要预先添加好配置信息。内部模块的巨大配置文件:yui3.js, 修改了模块的依赖关系时,还得维护该文件,不够方便。外部模块的配置信息,就是示例 YUI({modules:{...}}) 中的代码,也比较恼人。

进一步考虑普适性和 DRY 原则,还可以分析出以下不足:

  1. 信息冗余。math.js 文件名已经表明了该文件是 math 模块,但 YUI.add 里,还得显式指明模块名称。示例代码中的依赖信息也有冗余。
  2. 种子过大。yui-min.js + loader-min.js, gzip 前 53.3k, gzip 后依旧有 18k. 对于 seed 来说,这个大小是不能用“小巧”来形容的,特别是在国内网速下。
  3. add 的功能是纯注册;use 的功能,不仅包括下载,还管理了模块 factory 的执行,这有悖职责单一原则,不能延迟执行。
  4. 所有模块都依附到 Y 实例上。有部分模块的模块名和 Y 上命名空间不对应,比如 YUI().use('dd-drop', function(Y) { /*Y.DD*/ }), 这种不对应会加重使用者的记忆负担,不够直观。
  5. YUI3 的模块,仅能用于 YUI3, 普适性不是很好。

总之,在模块加载上,YUI3 很重,不光文件重,配置也重。在 CommonJS 时代,我们或许有更好的选择。

SeaJS 的尝试

SeaJS 的灵感来自 CommonJS 规范。Modules/2.0 规范目前还在讨论中:CommonJS Moules/2.0. SeaJS 遵循了规范里的大部分规定。其核心理念有:

  1. 职责单一原则:模块的声明、下载和执行是三个不同的步骤,在 API 的设计和实现上,应当尽量分离。
  2. 约定优于配置:模块所在路径和文件名,就是模块的标识,无需另行指定。这也是 DRY 原则的体现。
  3. 懒懒原则:能不执行的就先不执行,确实需要时才执行。

在 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 都演示完了:

  1. 声明模块:module.declare(id?, deps, factory)
  2. 提供模块:module.provide(ids, callback)
  3. 获取模块:在 factory 里调用 require(id)

表面上看起来, 和 YUI3 很类似。但从设计上分析,存在质的区别:

  1. YUI3 的模块信息基于配置,SeaJS 则基于约定;
  2. YUI3 将模块都依附到 Y 上,依旧存在命名空间;SeaJS 的设计里,通过 var xx = require('xx-id') 来获取,彻底脱离了对命名空间的依赖;
  3. exports 的设计,使得模块接口的暴露和模块之间的协作简单可靠;
  4. YUI3 的模块只能用于 YUI 类库,SeaJS 的模块可以用于 NodeJS, CouchDB 等环境下,更具有普适性。

从实现上看,SeaJS 还有以下优点:

  1. 代码非常小巧,目前 gzip 前 3.3k, gzip 后只有 1.7k.
  2. 非依赖项的模块文件是并行下载的;
  3. 模块代码,在第一次 require(id) 时才执行,这能节省初始 cpu 消耗,甚至整体消耗;
  4. 还有 data-main 等设置,使得页面里,只需引入 seajs/module.js 即可;
  5. 还有循环依赖的处理、相对路径的支持等等,遵循了 CommonJS 规范,普适性和灵活性上都很好。

更多功能可以看测试用例:Test Suite for module.js

目前 SeaJS 还在开发中,对于 packages 的支持、模块版本、时间戳、子模块等等,依旧还存在设计和摸索中,如果你有兴趣,非常欢迎 fork 以下代码:

seajs on github

 

分享到:
评论

相关推荐

    SeaJS(Javascript 模块加载框架) v1.0.2.zip

    SeaJS 是一个专门为 JavaScript 设计的模块加载框架,它的出现是为了应对 JavaScript 在大型项目中代码组织和管理的挑战。在 JavaScript 开发中,模块化是一个关键的实践,它有助于提高代码的可读性、可维护性和复用...

    SeaJS(Javascript 模块加载框架) v1.0.2

    SeaJS 是一款强大的JavaScript模块加载框架,其设计目标是遵循CommonJS规范,为开发者提供一个在浏览器环境中组织和管理代码的高效工具。CommonJS规范旨在促进JavaScript模块化,使得代码可复用性和可维护性得到显著...

    seajs源代码

    Seajs是一款轻量级的JavaScript模块加载器,它遵循CommonJS规范,旨在解决浏览器环境中的模块化问题。在深入理解seajs源代码之前,我们首先需要了解模块化的基本概念和CommonJS规范。 模块化是软件开发中的一种组织...

    SeaJS(Javascript模块加载框架)v0.9.1免费版

    SeaJS是中国开源社区贡献的一款JavaScript模块加载框架,其主要目标是为Web开发提供一种遵循CommonJS规范的模块化解决方案。这个框架的版本v0.9.1是一个免费版,适用于各种项目开发,帮助开发者更有效地组织和管理...

    seajs模块加载框架

    SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。

    seajs入门完整案例,适合新手学习

    2. **CMD(Common Module Definition)规范**:Seajs 遵循 CMD 规范,它强调的是异步加载模块,这使得页面能够按需加载,提高页面性能。CMD 规范的两个核心概念是 `require` 和 `exports`,用于模块的引入和导出。 ...

    seajs-2.3.0.zip

    Seajs是中国开源社区非常受欢迎的一款JavaScript模块加载器,它的出现为Web开发引入了CommonJS规范,使得前端开发更加模块化,便于代码管理和维护。Seajs 2.3.0是该库的一个稳定版本,提供了丰富的功能和优化。 一...

    SeaJS与RequireJS区别

    **SeaJS 和 RequireJS 是两种广泛使用的 JavaScript 模块加载器和依赖管理工具,它们的主要目的是解决 JavaScript 在浏览器端的异步加载和模块化问题。** **SeaJS** SeaJS 是一个轻量级的模块加载器,由中国淘宝...

    seajs js 模块加载器

    SeaJS 是一款专为Web端设计的JavaScript模块加载器,它的出现是为了解决JavaScript在浏览器环境中的组织和管理问题。随着Web应用的复杂度不断提升,JavaScript代码的组织和依赖管理变得至关重要,SeaJS 提供了一种...

    简易实现seajs模块转换成esmodules模块的脚本

    Seajs是早期广泛使用的CMD(Common Module Definition)规范的实现,而ES Modules则是现代浏览器和Node.js原生支持的模块系统。本文将详细介绍如何通过脚本将Seajs模块转换为ES Modules,并探讨这两种模块系统的差异...

    SeaJS(Javascript 模块加载框架) v0.9.0.rar

    SeaJS 是一个遵循 CommonJS 规范的模块加载框架,可用来轻松愉悦地加载任意 JavaScript 模块

    seajs-2.2.0源码

    1. **模块加载策略**:Seajs采用`CMD (Common Module Definition)`模式,即命令式模块定义。模块的加载和执行是异步的,只有当模块被实际引用时才会加载,这提高了页面的加载效率。 2. **模块标识**:模块可以通过...

    SeaJS(Javascript 模块加载框架)源代码

    SeaJS 是一款强大的 JavaScript 模块加载框架,其设计灵感来源于 CommonJS 规范,旨在为前端开发者提供一种模块化开发的方式,使 JavaScript 代码更加结构化、易于管理和复用。SeaJS 的核心目标是让在浏览器环境中...

    seaJS框架简介和完整例子

    SeaJS 是一个轻量级的前端模块加载器,它的出现是为了改善JavaScript在浏览器环境中的组织和加载方式。本文将深入探讨SeaJS的基本概念、工作原理以及如何通过一个完整的例子来理解其用法。 SeaJS的核心理念是遵循 ...

    seajs手册,教程

    Seajs是中国开源社区发展出来的一款轻量级的前端模块化加载器,它的出现是为了应对JavaScript在浏览器端组织和管理代码的复杂性。本手册将详细阐述Seajs的核心概念、使用方法以及如何通过它来构建高效的前端应用。 ...

    seajs_master.zip

    1. **模块化管理**:Seajs实现了CMD(Common Module Definition)规范,允许开发者在浏览器端定义、加载和使用模块。CMD与服务器端的CommonJS类似,但延迟执行和异步加载是其显著特点,适合浏览器环境。 2. **模块...

    seajs_2.3.0以及学习文档

    Seajs 是一个轻量级的前端模块加载器,它的出现是为了在浏览器端实现 CommonJS 规范,使得 JavaScript 的组织和开发变得更加模块化。Seajs 版本 2.3.0 是其稳定的一个版本,提供了更完善的特性和优化。 在...

    seaportjs:seajs的精简版

    在上面提到的场景下,其实seajs仅仅需要处理模块管理,对于大部分代码完成的模块加载其实是不需要的,如果在这时使用Seaport替代seajs,会大幅减少基础文件的请求体积。对于患有轻度代码洁癖的患者来说这可是一剂...

    seajs下载以及规范

    Seajs是中国开源社区推出的一款基于模块化开发的前端加载器,它借鉴了CommonJS的模块化思想,但针对浏览器环境进行了优化。Seajs的核心理念是让JavaScript模块化变得简单,帮助开发者解决在大型Web项目中代码组织、...

    seajs-2.1.1.rar

    Seajs是中国著名的前端模块加载器,它借鉴了CommonJS的规范,使得JavaScript在浏览器环境中也能实现模块化的开发。这个“seajs-2.1.1.rar”压缩包包含的是Seajs的2.1.1版本,这是一个稳定且广泛使用的版本。下面我们...

Global site tag (gtag.js) - Google Analytics