1. AMD的由来
前端技术虽然在不断发展之中,却一直没有质的飞跃。除了已有的各大著名框架,比如Dojo,JQuery,ExtJs等等,很多公司也都有着自己的前端开发框架。这些框架的使用效率以及开发质量在很大程度上都取决于开发者对其的熟悉程度,以及对JavaScript的熟悉程度,这也是为什么很多公司的技术带头人都喜欢开发一个自己的框架。开发一个自己会用的框架并不难,但开发一个大家都喜欢的框架却很难。从一个框架迁移到一个新的框架,开发者很有可能还会按照原有框架的思维去思考和解决问题。这其中的一个重要原因就是JavaScript本身的灵活性:框架没办法绝对的约束你的行为,一件事情总可以用多种途径去实现,所以我们只能在方法学上去引导正确的实施方法。庆幸的是,在这个层面上的软件方法学研究,一直有人在去不断的尝试和改进,CommonJS就是其中的一个重要组织。他们提出了许多新的JavaScript架构方案和标准,希望能为前端开发提供银蛋,提供统一的指引。
2. AMD是什么
作为一个规范,只需定义其语法API,而不关心其实现。AMD规范简单到只有一个API,即define函数:
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);
其中:
- module-name: 模块标识,可以省略。
- array-of-dependencies: 所依赖的模块,可以省略。
- module-factory-or-object: 模块的实现,或者一个JavaScript对象。
从中可以看到,第一个参数和第二个参数都是可以省略的,第三个参数则是模块的具体实现本身。后面将介绍在不同的应用场景下,他们会使用不同的参数组合。
从这个define函数AMD中的A:Asynchronous,我们也不难想到define函数具有的另外一个性质,异步性。当define函数执行时,它首先会异步的去调用第二个参数中列出的依赖模块,当所有的模块被载入完成之后,如果第三个参数是一个回调函数则执行,然后告诉系统模块可用,也就通知了依赖于自己的模块自己已经可用。如果对应到dojo1.6之前的实现,那么在功能上可以有如下对应关系:
- module-name: dojo.provide
- dependencies: dojo.require
- module-factory: dojo.declare
不同的是,在加载依赖项时,AMD用的是异步,而dojo.require是同步。异步和同步的区别显而易见,前者不会阻塞浏览器,有更好的性能和灵活性。而对于NodeJs这样的服务器端AMD,则模块载入无需阻塞服务器进程,同样提高了性能。
3. AMD实例:如何定义一个模块
下面代码定义了一个alpha模块,并且依赖于内置的require,exports模块,以及外部的beta模块。可以看到,第三个参数是回调函数,可以直接使用依赖的模块,他们按依赖声明顺序作为参数提供给回调函数。
这里的require函数让你能够随时去依赖一个模块,即取得模块的引用,从而即使模块没有作为参数定义,也能够被使用;exports是定义的alpha 模块的实体,在其上定义的任何属性和方法也就是alpha模块的属性和方法。通过exports.verb = ...就是为alpha模块定义了一个verb方法。例子中是简单调用了模块beta的verb方法。
4. 匿名模块
define 方法允许你省略第一个参数,这样就定义了一个匿名模块,这时候模块文件的文件名就是模块标识。如果这个模块文件放在a.js中,那么a就是模块名。可以在依赖项中用"a"来依赖于这个匿名模块。这带来一个好处,就是模块是高度可重用的。你拿来一个匿名模块,随便放在一个位置就可以使用它,模块名就是它的文件路径。这也很好的符合了DRY(Don't Repeat Yourself)原则。
下面的代码就定义了一个依赖于alpha模块的匿名模块:
5. 仅有一个参数的define
前面提到,define的前两个参数都是可以省略的。第三个参数有两种情况,一种是一个JavaScript对象,另一种是一个函数。
如果是一个对象,那么它可能是一个包含方法具有功能的一个对象;也有可能是仅提供数据。后者和JSON-P非常类似,因此AMD也可以认为包含了一个完整的 JSON-P实现。模块演变为一个简单的数据对象,这样的数据对象是高度可用的,而且因为是静态对象,它也是CDN友好的,可以提高JSON-P的性能。考虑一个提供中国省市对应关系的JavaScript对象,如果以传统JSON-P的形式提供给客户端,它必须提供一个callback函数名,根据这个函数名动态生成返回数据,这使得标准JSON-P数据一定不是CDN友好的。但如果用AMD,这个数据文件就是如下的形式:
假设这个文件名为china.js,那么如果某个模块需要这个数据,只需要:
通过这种方式,这个模块是真正高度可复用的,无论是用远程的,还是Copy到本地项目,都节约了开发时间和维护时间。
如果参数是一个函数,其用途之一是快速开发实现。适用于较小型的应用,你无需提前关注自己需要什么模块,自己给谁用。在函数中,可以随时require自己需要的模块。例如:
即你省略了模块名,以及自己需要依赖的模块。这不意味着你无需依赖于其他模块,而是可以让你在需要的时候去require这些模块。define方法在执行的时候,会调用函数的toString方法,并扫描其中的require调用,提前帮助你载入这些模块,载入完成之后再执行。这使得快速开发成为可能。需要注意的一点是,Opera不能很好的支持函数的toString方法,因此,在浏览器中它的适用性并不是很强。但如果你是通过build工具打包所有的 JavaScript文件,这将不是问题,构建工具会帮助你扫描require并强制载入依赖的模块。
6. Dojo中的AMD
Dojo 在三月初正式发布了1.6版本,其中一个重要的变化就是引入了AMD机制,取代了原来的dojo.provide和dojo.require方法。但是现在仍然保持了向后兼容性,你仍然可以用dojo.provide和dojo.require来定义和加载模块。需要注意的是:在 Dojo 1.6 中, 针对 AMD 的重构仍然属于一个过渡期的改动 , 用户自己开发的 AMD 模块还不能被 Dojo 的加载器和 Build 系统支持 . 1.6 中现有的编译系统对AMD的支持还非常局限。 如果你自己开发了 AMD 格式的模块,并且你仍然在使用默认的 Dojo 同步模块加载器,那么你必须严格遵循 Dojo 模块的格式 ( 包括换行的格式 ) 来保证你自己的模块能够成功编译。总结起来有以下三点:
- 用传统的方法 (dojo.require()/dojo.provide()) – 这些模块,只能被 Dojo 同步加载器 加载,但可以被 Dojo 编译系统(Build System )正确的编译
- 用 Dojo 同步加载器来加载 AMD 格式 ( define ()) 模块 – 这些模块可以被正常的加载,并且可以被其他兼容 AMD 格式的加载器加载 . 现在虽然 Dojo1.6 还没有正式支持这种用法, 但在目前的 Dojo1.6 编译系统中,是可以正常工作的 . ( 前提是你必须严格遵循 Dojo 模块定义的代码规范 )
- 使用第三方加载器来加载 AMD 格式( define ())模块 – 模块可以被正常加载,并且可以被其他加载器所使用 . 这些模块可以使用 RequireJS 或 Backdraft 提供的编译系统正常编译,但是 Dojo 还没有正式的测试过和其他加载器的兼容性 .
以Calendar为例,用define方法来定义这个模块:
可以看到,模块标识就是模块文件的路径,模块本身一般都是dojo.declare定义的类。Dojo1.6中的dojo和dijit命名空间下的模块均已经用AMD的形式进行了重构,但dojox下仍然延用了传统的dojo.provide和dojo.require形式。对AMD的引入是Dojo走向自动化包管理的重要一步,在后续文章中我们也将继续关注Dojo在这方面的进展。
7. 结论
AMD 规范是JavaScript开发的一次重要尝试,它以简单而优雅的方式统一了JavaScript的模块定义和加载机制,并迅速得到很多框架的认可和采纳。这对开发人员来说是一个好消息,通过AMD我们降低了学习和使用各种框架的门槛,能够以一种统一的方式去定义和使用模块,提高开发效率,降低了应用维护成本。
参考资料:
Dojo 中文博客
RequireJS/AMD Module Forms
Modules/AsynchronousDefinition
本文已经首发于InfoQ中文站,版权所有,原文为《Dojo1.6新特性:再谈AMD规范》,如需转载,请务必附带本声明,谢谢。
InfoQ中文站是一个面向中高端技术人员的在线独立社区,为Java、.NET、Ruby、SOA、敏捷、架构等领域提供及时而有深度的资讯、高端技术大会如QCon、线下技术交流活动QClub、免费迷你书下载如《架构师》等。
分享到:
相关推荐
Dojo 1.6版本是在2011年发布,它引入了AMD(Asynchronous Module Definition)模块定义规范,使得模块化开发更加高效。 ### AMD规范 AMD规范是一种在浏览器环境中异步加载和定义JavaScript模块的方式。它允许模块和...
dojo 1.6 api包含dojo、dojox、dijit等3个部分的api。
标题中的"dojo1.6官网"表明我们关注的是Dojo框架的1.6版本。这个版本在当时是相当成熟且广泛使用的,它包含了Dojo的核心组件、模块化系统、UI部件以及许多其他实用工具。 Dojo 1.6 的主要特点和知识点包括: 1. **...
在Dojo 1.6版本中,DOM操作是其核心特性之一,它允许开发者高效地创建、修改和管理HTML元素。以下是对Dojo 1.6 DOM相关操作的详细说明: 1. **dojo.query**: 这是Dojo提供的一个强大选择器,类似于jQuery的`$`函数...
标题中的"dojo v1.6 官方最新版同步下载.zip"指的是Dojo框架的1.6版本,这是一个官方发布的更新版本,可能包含了性能优化、新特性、修复的bug以及对之前版本的改进。 Dojo 1.6 版本主要知识点包括: 1. **模块系统...
<<Dojo的高级运用:Widget的制作>> 和 使用Dojo和JSON构建Ajax应用>> 中涉及到的源代码 博文链接:https://tailsherry.iteye.com/blog/102907
综上所述,DOJO是一个强大的JavaScript开发工具,其模块化、跨浏览器的特性和丰富的Widget系统使其成为开发RIA的首选之一。通过深入理解和熟练使用DOJO,开发者可以大大提高工作效率,创建出功能丰富、用户体验优良...
- AMD(Asynchronous Module Definition)是Dojo引入的一种模块加载方式,它允许异步加载模块,提高页面加载速度。 - `dojo/require` 和 `dojo/ready`:用于在页面加载完成后执行特定代码,确保DOM和所有依赖项...
2. **AMD 模块系统**: AMD是Dojo 1.6引入的重要特性,它允许异步加载JavaScript模块,解决了大型应用中因脚本顺序依赖导致的性能问题。require.js是基于AMD实现的一个知名库,而Dojo 1.6是最早采用这一模式的库之一...
- `dojo/ready`: 确保DOM加载完成后再执行代码,类似于jQuery的$(document).ready()。 2. Dojo Widgets(组件): Dojo 的强大之处在于其丰富的Widget系统。`dojo_widget.doc` 可能详细介绍了这些组件,如按钮、...
1. **模块系统**:Dojo使用AMD(Asynchronous Module Definition)模块定义协议,允许异步加载模块。`require`和`define`是两个关键函数,`require`用于加载模块,`define`用于定义模块。 2. **dojo/_base**:这是...
Dojo的核心特性包括模块化系统(基于AMD规范)、DOM操作、动画效果、数据绑定、事件处理、国际化支持以及对多种设备和浏览器的良好兼容性。1.8.1版本的更新可能包含了性能优化、API改进、bug修复和对新标准的适应,...
1. **模块化系统(Dojo Loader)**:Dojo 1.2.3采用了AMD(Asynchronous Module Definition)规范,使得开发者可以异步加载和组织代码,提高页面性能,避免一次性加载整个库。`dojo.require` 和 `dojo.provide` 是...
Dojo 1.7 引入了AMD,这是一种异步模块定义的加载机制,允许开发者按需加载模块,提高了页面性能。通过`require()`函数,我们可以方便地引入和依赖其他模块。 2. **Dijit UI 库:** Dijit是Dojo的UI组件库,包含...
【Dojo(1.7.2) AMD Demo】是一个基于Dojo 1.7.2版本的异步模块定义(Asynchronous Module Definition, AMD)的示例项目。...你可以通过官方文档、教程和相关博客(如给出的链接)来深入学习和实践Dojo 1.7.2的AMD特性。
7. **dojo/Deferred和dojo/promise**:Dojo的异步处理机制基于`dojo/Deferred`,它是Promise/A+规范的实现,处理回调和链式调用,使得异步编程更加优雅。 8. **dojo/ xhr和dojo/io**:Dojo的`dojo/xhr`和`dojo/io`...
6. **AMD (Asynchronous Module Definition)**:Dojo是AMD模块定义规范的先驱,这种加载机制使得模块化开发更加高效,可以异步加载所需代码,避免阻塞页面渲染。 7. **Internationalization (i18n)**:Dojo提供了...
1. **模块化系统**:Dojo 1.7 引入了AMD(Asynchronous Module Definition)模块加载机制,这允许异步加载JavaScript模块,优化了页面性能,避免了整体加载导致的阻塞。通过`require`和`define`函数,开发者可以轻松...