即刻成为鸿蒙应用开发者,解锁职业发展新机遇!点击了解~ 了解详情
写点什么

Dojo 1.8:向完美架构继续前行

  • 2012-10-15
  • 本文字数:4541 字

    阅读完需:约 15 分钟

Dojo 1.8 已正式发布数星期,作为 Dojo 的铁杆粉却直到今天才来总结,实在心有不安,但这并不妨碍我们来看一看那些让人眼前一亮的新特性。作为历史最悠久的 RIA 框架,Dojo 的发展一直不冷不热。比起后来者 JQuery 的大红大紫,Dojo 则默默的按照自己的步伐坚定的前行着。而对完美架构的追求,则构成了 Dojo 前行的主旋律,这也使得 Dojo 一直拥有一批坚定的支持者。

Dojo 显然并不重视设计灵巧的 API,但却非常看重编程思想的应用,以及对前端架构的研究。我们现在就来看看 Dojo 1.8 是如何在这个方向上继续努力着。

1. 对匿名模块的彻底支持:dojo/parser 支持了对模块 ID 的解析

从上个 1.7 版本开始,Dojo 全面引入了 AMD(Asynchronous Module Definition)的机制。这使得每个模块的逻辑都完全拥有自己的闭包,通过返回值来暴露 API 接口或者数据。这样的模块是完全匿名的,AMD Loader 会根据模块 ID(例如:dojo/html)来映射到路径去寻找对应的文件。比起旧的 Loader 中每个模块都需要声明 dojo.provide(‘dojo.html’),AMD 机制真正做到了 DRY 原则(Don’t Repeat Yourself),模块路径就是唯一标识符,不再需要在模块内部重复指定自身路径。这样的架构也让 Dojo 几乎可以做到完全没有全局变量的存在,说几乎是因为 1.8 之前有一个例外:通过 Html 声明方式创建的 widget 仍然需要一个全局的 data-dojo-type 属性:

复制代码
<input type="text" data-dojo-type="dijit.form.TextBox"/>

这里的 dijit.form.TextBox 就是一个全局变量,表示一个 TextBox 控件的类名。在原来的 dijit/form/TextBox 模块中,必须有一个定义:

复制代码
declare('dijit.form.TextBox', [], {});

dojo 的 parser 会根据这个 Widget 的 data-dojo-type 去找对应的实现类。所以,尽管作为 AMD 模块已经是匿名,但其却有一个隐藏的全局变量在模块内定义,导致其自身其实并不是真正意义上的匿名,即不是完全的 DRY。

然而在 1.8 中,这最后一个局限也完全消失了。dojo/parser 能够根据模块 ID 来找到 TextBox 的实现,现在我们可以这样声明一个 Widget:

复制代码
<input type="text" data-dojo-type="dijit/form/TextBox"/>

尽管表面上看来,只是把点(.)换成了斜杠(/),但从编程的思想上来看,则可以让模块减少了一个概念:一个 Widget 就只有一个标识,就是模块 ID。而不是之前既有模块 ID,又有 Widget 类名这样容易混淆的情形。概念上的简单和清晰是理解易维护的重要前提。

本质上来看,AMD 取代传统的 dojo.require 无关乎性能,仅关乎于架构。AMD 能让你沿着正确的路线开发松耦合的模块,让应用更加容易理解和维护。而 Dojo 正在不断的完善着细节,帮助我们设计出更好的应用架构。

2. 让每个 Widget 都有插件机制:新的 data-dojo-mixins 属性

插件机制是建立灵活可扩展应用的一个最佳实践,而现在 Dojo 通过这个全新的属性全面实现了插件机制,让 Dojo 的 Widget 在使用时可以灵活决定自己需要的特性。因为这个属性的存在,Widget 的开发也将可以更加模块化,每一组功能都能独自定义。在使用的时候,根据具体的使用场景,来决定是否启用此功能。比如,在 dojox 中提供了最近较为流行的 TreeMap 组件。模块 dojox/treemap/TreeMap 本身仅仅包含了最基础的功能。而对于键盘支持,色块拆分等功能则通过可插拔的模块来实现:dojox/treemap/Keyboard 和 dojox/treemap/DrillDownUp 模块。这样的附属模块可以理解为插件,按照需要将其添加到 data-dojo-mixins 属性中即可开启相应的功能。

复制代码
<div data-dojo-type="dojox/treemap/TreeMap" data-dojo-mixins="dojox/treemap/Keyboard, <br></br>dojox/treemap/DrillDownUp"></div>

在这里,data-dojo-mixins 属性中用逗号隔开的模块就可以看成一个个插件。不仅新控件可以利用插件机制,为现有组件添加新的功能,也可以通过提供插件来实现。比起派生一个新类来实现此功能,插件是可以通用的。例如:假设要为 dijit/form 下的 TextBox,Select 等表单控件添加语音识别的功能,可能只需要写一个 my/voice/Recognizer 模块,这样具有 set(‘value’, value) 这样接口的 Widget 都将能灵活选用这个组件,而不需要为每个 Widget 都派生一个新的类。而对于多个插件的功能组合,则更显然 data-dojo-mixins 会非常合适。

现在看到的是声明方式创建的 Widget 我们可以很好的利用 data-dojo-mixins 实现插件机制。那么对于动态创建的 Widget 呢?其实这 1.8 之前已经可以实现:

复制代码
var treemap = new (declare(['dojox/treemap/TreeMap', 'dojox/treemap/Keyboard',<br></br> 'dojox/treemap/DrillDownUp']))(arguments);

模块的灵活性,一直是 Dojo 的重点关注。从引入 AMD 开始,Dojo 就提出了 base-less 的概念,即 Dojo 框架可以配置为没有任何核心库,所有的模块都按需加载。这要求每个模块提供的功能独立而精简,从而能够实现最终仅仅加载需要的代码的目的。而 data-dojo-mixins 属性则是可以帮助我们将功能拆分并模块化到极致。这在目前 JavaScript 代码普遍臃肿的大环境下无疑是一个让人眼前一亮的概念和做法。

3. 契约式编程:dojo/promise

契约式编程是另一种很好的编程实践,它的目标是让程序的各个模块各司其职,仅仅关注自己需要完成的事情,而不用去关心其它模块该关心的事情。从而可以降低模块之间的耦合度,同时也让程序在语义上更加容易理解。其概念已经非常成熟,读者可以搜索相关资料,这里不再赘述。

虽然在 1.8 之前,Dojo 可以通过 dojo.Deffered 实现契约编程的思想,但是终归不是很正式。而从 1.8 起,Dojo 提供了正式的类和 API 来全面支持契约式编程:

dojo/promise/Promise - 契约核心类,所有实现契约机制的类都能够提供一个 Promise 类的实例。比如 dojo/Deffered,专门对应于异步的情形。

dojo/errors/CancelError - 当一个契约被未知原因的取消时,提供此默认错误。

dojo/promise/all - 接受多个契约作为参数,返回一个新的契约。只有当多个契约都得到满足时,新契约才会得到满足。从本质看,这取代了原来的 dojo/DeferredList。

dojo/promise/first - 接受多个契约作为参数,返回一个新的契约。只要其中一个契约得到满足时,新契约立刻满足。

举例:

复制代码
require(["dojo/promise/all", "dojo/Deferred", "dojo/dom", "dojo/on", "dojo/json", "dojo/domReady!"],
function(all, Deferred, dom, on, JSON){
function googleRequest(){
var deferred = new Deferred();
setTimeout(function(){
deferred.resolve("foo");
}, 500);
return deferred.promise;
}
function bingRequest(){
var deferred = new Deferred();
setTimeout(function(){
deferred.resolve("bar");
}, 750);
return deferred.promise;
}
function baiduRequest(){
var deferred = new Deferred();
setTimeout(function(){
deferred.resolve("baz");
}, 1000);
return deferred.promise;
}
on(dom.byId("startButton"), "click", function(){
dom.byId("output").innerHTML = "Running...";
all([googleRequest(), bingRequest(), baiduRequest()]).then(function(results){
dom.byId("output").innerHTML = JSON.stringify(results);
});
});
});

通过这段代码可以看到,对每个搜索引擎的搜索请求都返回一个契约,外界程序只需关心这个契约。在搜索完成之后,契约会通过调用 resolve 方法来告诉外界自己已完成任务。从而外界仅需要关心什么时候开始搜索,以及搜索完成后自己该做什么。其逻辑和语义都非常清楚和合理。通过 promise 提供的 all,first 方法,外界可以更灵活的对契约进行管理。

通过 promise,请求发起和结果处理过程被严格的区分开来,你将不得不分开代码处理逻辑,这种隐含的硬性规定让代码程序结构更加良好,代价是会让初用者觉得上手困难,但是一旦习惯,带来的好处将是一劳永逸的。

4. 更为统一的 IO 模块:dojo/request

所有的 RIA 框架都会通过隐藏底层细节,提供统一的一致的 API 来实现跨浏览器的支持。而现在 Dojo 正在将跨浏览器扩展到跨 JavaScript 环境。dojo/request 正是有这样需求的一个 API。在浏览器端,通过 XMLHttpRequest 获取数据,而在 NodeJs 之类 JavaScript 环境则用 NodeJS 提供的文件系统 API 来实现。

dojo/request 这个 package 引入了一种用于异步请求的全新架构。这个模块将用户从具体的请求细节中抽象出来,也就是说,用户无需关心请求是如何发生的。dojo/request 正是基于上文提到的 dojo/promise 来构建的。当引入 dojo/request 模块时,将根据运行平台自动返回对应的实现。比如,浏览器中就会使用 dojo/request/xhr,而 NodeJS 平台则会使用 dojo/request/node。

下面的代码演示了 dojo/request 的基本用法:

复制代码
require(["dojo/request"], function(request){
var promise = request(url, options);
promise.then(
function(data){
},
function(error){
}
);
promise.response.then(
function(response){
},
function(error){
}
);
request.get(url, options).then(...);
request.post(url, options).then(...);
request.put(url, options).then(...);
request.del(url, options).then(...);
});

详细的 dojo/request 的介绍大家可以参考 Dojo 中文博客的文章:深入浅出 dojo/request: http://blog.csdn.net/dojotoolkit/article/details/7991286

5. 面向移动设备的全面支持:dojo/touch,dojox/mobile

dojo/touch 模块的目的是为了让面向 PC 的 Web 应用也能够运行在移动设备上,它提供了许多键盘鼠标事件和手势操作的映射。从而让普通的控件在移动设备上也能正常工作。现在 Dojo 自带的控件基本都采用了 dojo/touch 来实现对移动设备的支持。对于自定义的控件,也可以通过 dojo/touch 模块来实现这一功能。

Mobile 是最近的热点领域,HTML5 能够让同一份代码运行在不同的平台上。虽然有些类型的应用并不适合使用 HTML5,但大多数信息展示和简单交互的移动应用非常适合使用 HTML5,能够大大减少开发维护成本。而 Dojo 1.8 在对 Mobile 设备提供了大力的支持,提供了多达 28 个全新的控件,比如 TreeView,ScrollablePane,DatePicker,GridLayout 等常用控件。通过 PhoneGap+Dojo 把 HTML5 封装成手机应用,将是一个完全免费的开源跨平台移动开发解决方案。这也正是 IBM 使用的解决方案。

小结

Dojo 一直非常看重编程思想的使用,以及前端架构的优化。比如 1.8 中的契约式编程,AMD 增强,等等。虽然提供了大量新的 API,但是为了保证向后兼容仍然保留了原有的 API,只是会标识为已过期。这些过期的 API 将会在明年发布的 2.0 版本中彻底删除。这在一定程度增加了升级的难度,但是为了软件的健壮和可维护性,这是值得付出的代价。1.8 和 1.9 版本也使得到 2.0 的过渡更加平滑。总体来说,我相信随着大家对 Dojo 的深入了解,Dojo 一定会出现在越来越多的大型项目之中。

参考资源:

Dojo 1.8 下载: http://dojotoolkit.org

Dojo 1.8 Release Notes: http://dojotoolkit.org/reference-guide/1.8/releasenotes/1.8.html

Dojo 中文博客: http://blog.csdn.net/dojotoolkit

Dojo 新浪微博: http://weibo.com/dojotoolkit

2012-10-15 02:005581

评论

发布
暂无评论
发现更多内容

来2023用友BIP技术大会,与北京地铁等领先企业探索数智化转型路径

用友BIP

技术大会 用友iuap 用友技术大会 数智底座 技术底座

小红书自研小程序:电商体验与效果优化的运行时体系设计

小红书技术REDtech

架构 前端

尚硅谷CDH 6.3.2视频教程发布

小谷哥

T 级数据量迁移!知名云巨头如何从 Jira 切换至 ONES?

万事ONES

捷行十周年庆,惊喜活动

ShineScrum

大普微DapuStor完成阿里云PolarDB数据库产品生态集成认证

阿里云数据库开源

国产数据库 polarDB PolarDB-X PolarDB-PG 大普微

低代码开发,是稳打稳扎还是饮鸩止渴?

引迈信息

前端 低代码 JNPF

MobPush创建推送

MobTech袤博科技

天天预约|如何使用「代预约」功能?全在这篇文章里!

天天预约

线上预约 预约工具 预约 预约小程序

想让 ChatGPT 帮忙进行数据分析?你还需要做......

Kyligence

数据分析 指标平台

理一理事务实现

Zhang

MySQL 事务 数据库·

重新理解RocketMQ Commit Log存储协议

Apache RocketMQ

RocketMQ 消息队列

540p秒变1080p!小红书端侧实时超分带你免流量玩嗨短视频

小红书技术REDtech

AI 算法 短视频

AIGC爆火的背后需要掌握的基础原理

飞桨PaddlePaddle

人工智能 AI 百度飞桨 AIGC

图文介绍 Windows 系统下打包上传 IOS APP 流程

ios 开发

中南财经政法大学教授施先旺:事项法会计促进业财合一和会计变革

用友BIP

技术大会 业财合一 业财融合 事项会计

什么是文件传输协议,文件传输协议又是怎么工作的

镭速

公厕一体化智慧管理解决方案@光明源智能科技

光明源智慧厕所

智慧城市

降本增效不是“盲目减脂”,利用亚马逊云科技达成云成本正循环

Lily

软件测试/测试开发丨电商业务的性能测试必备基础知识

测试人

软件测试 Jmeter 性能测试 测试开发

上干货!小红书“薯条”业务竞价策略及最优公式详解

小红书技术REDtech

广告 机制策略

例行汇报,看看 FinClip 3月都干了啥

FinClip

实力担当!焱融文件存储再次中标中国移动项目

焱融科技

#高性能 #分布式文件存储 #文件存储 #中国移动

一站式指标平台 Kyligence Zen 登陆亚马逊云科技 Marketplace

Kyligence

数据分析 指标中台

京东技术专家首推:微服务架构深度解析,GitHub星标120K

程序知音

Java 微服务 springboot java架构 Java进阶

在高并发场景下保证数据一致性:sync.Map的并发安全性实践

Jack

码头风云——5G降临

脑极体

5G

人人可用的敏捷指标工具!Kyligence Zen 正式发布 GA 版

Kyligence

数据分析 Kyligence Zen 指标平台 大数据管理

软件测试/测试开发丨UI自动化测试,PageObject设计模式

测试人

软件测试 自动化测试 测试开发 UI自动化 pageobject

从一场文学奖评选,看金山文档To B 转型怎么走

B Impact

Dojo 1.8:向完美架构继续前行_Java_王沛_InfoQ精选文章