使用Dojo的 defer延迟) 方法的基本知识

作者: Bryan Forbes

译者: feijia (tiimfei@gmail.com)

原文连接: http://dojotoolkit.org/documentation/tutorials/1.6/deferreds/

适用dojo 版本: 1.6

难度: 中等

在本教程中, 你将学到使用Dojo的 defer(延迟) 方法的基本知识。

使用延迟方法,可以优雅轻松的处理在JS编程中常见的异步调用。我们还将解释如何使用DeferredList,它能够一次处理多个延迟的异步调用。

入门

初听起来, “延迟" (Deferred) 这个名字颇为神秘。但它其实是一个Dojo提供给我们用来处理异步调用(例如Ajax)的强大工具. 简单来说,一个Deferred对象它会等待一段时间再去执行指定的调用,直到某个特定的事件发生或者前一个动作完成。Ajax就是一种常见的例子: 发出一个Ajax请求之后,我们需要等待服务器把响应返回之后才会调用处理函数。所以Deferred对象提供给我们的就是这种将某个动作延迟并等待某个事件发生的能力。在本教程中,我们将会结合Ajax教程的内容一起来解读如何使用Deferred对象更好的管理异步的JS程序。

dojo.Deferred

延迟的概念并非Dojo专有,(译者:Jquery等其他JS框架也有类似的对象和实现, CommonJS 组织还为此定义了一套标准),从0.3 版本开始Dojo就实现了dojo.Deferred对象。

Deferred对象有三个状态,初始化时是"unresolve” 状态,当它所等待的事件发生时,进入"resolve" 状态, 第三种状态是出错状态,即该事件没有按照预期的发展,例如服务器端返回了错误消息,也称reject 状态.

创建Deferred对象后,我们可以通过调用该对象的then方法注册一个回调函数,表示当这个Deferred对象等待的某个事件发生时(resolve),就调用该回调函数。then 方法还接受第二个参数,可以制定当事件失败或出错时(reject)时调用的出错回调函数 .

让我们来看一个例子:

  1. vardef=newdojo.Deferred(),
  2. userlist=dojo.byId("userlist");
  3. def.then(function(res){
  4. //Thiswillbecalledwhenthedeferred
  5. //isresolved
  6. dojo.forEach(res,function(user){
  7. dojo.create("li",{
  8. id:user.id,
  9. innerHTML:user.username+":"+user.name
  10. },userlist);
  11. });
  12. function(err){
  13. //Thiswillbecalledwhenthedeferred
  14. //isrejected
  15. innerHTML:"Error:"+err
  16. });
  17. dojo.xhrGet({
  18. url:"users.json",
  19. handleAs:"json",0); background-color:inherit">load://Resolvewhencontentisreceived
  20. def.resolve(res);
  21. error:function(err){
  22. //Rejectonerror
  23. def.reject(err);
  24. }
  25. });

查看示例

在上面的示例中,我们创建了一个dojo.Deferred 对象并在上面分别注册了一个成功回调函数和出错回调函数。我们还调用了dojo.xhrGet 一个异步Ajax调用,去服务器端获取"user.json"。 如果这个ajax调用成功了,我们在xhr对象的load属性所设的回调函数中会将dojo.Deferred对象置为resolve状态 ,这时我们在该Deferred对象上注册的回调函数将会被调用;如果ajax调用失败,则Deferred上注册的错误回调函数将会被调用。

上面的例子,你可能会觉得是多此一举,为什么不直接在xhrGet里直接分别设定成功和失败的回调函数呢? 是的,你的确可以这么做,但是通过引入Deffered对象,我们把负责处理服务器端返回数据的逻辑(回调函数)和发送Ajax请求的逻辑进行了解藕。

实际上,为了方便开发者使用Deffered对象,Dojo的Ajax构造函数方法会直接返回给你一个Deferred对象,因此上面的代码可以简化不少:

vardef=dojo.xhrGet({
  • handleAs:"json"
  • varuserlist=dojo.byId("userlist");
  • //Thisshouldn'toccur,butit'sdefinedjustincase
  • alert("Anerroroccurred:"+err);
  • });
  • 查看示例

    在这个例子中我们不再需要设置dojo.xhrGet的 load属性了,可以直接在xhrGet返回的Deferred对象上通过then来注册回调函数. 代码逻辑更加直观简洁.

    在回调函数中,我们遍历了从服务器端返回的用户列表,并且为每个用户创建了一个HTML列表 。 从功能上看,和前一个例子完全一样,但是在这个例子中,我们得以把处理服务器端数据的逻辑和发送Ajax请求的逻辑分开了。 所以Deferred对象的一个重要功能就是对我们的程序逻辑进行解藕。 (decoupling)

    链式调用

    dojo.Deferred是个挺容易理解的概念,但是它还有一些很强大的功能值得我们继续探索. 其中之一就是链式调用(Chaining):每个then方法的返回值都仍然是一个Defered对象。 我们来看一个例子:

    假设前面的例子里服务器端返回的不是JSON格式的用户对象,而是每个用户的信息的原始值。 值当然不如对象方便使用,所以我们希望注册一个回调函数来把这些原始数值转换为用户对象。

    varoriginal=dojo.xhrGet({
  • url:"users-mangled.json",153); font-weight:bold; background-color:inherit">varresult=original.then(varuserlist=dojo.byId("userlist1");
  • returndojo.map(res,innerHTML:dojo.toJson(user)
  • return{
  • id:user[0],0); background-color:inherit">username:user[1],
  • name:user[2]
  • };
  • //由original的then方法返回的result对象也有一个`then`方法来接受回调函数,和original对象一样。
  • //但是要注意的是传给result.then中注册的回调函数的值,不是Ajax调用获取的数据,而是original的回调函数的返回值。
  • //也就是已经经过格式转换的用户对象map
  • result.then(function(objs){
  • varuserlist=dojo.byId("userlist2");
  • dojo.forEach(objs,153); font-weight:bold; background-color:inherit">function(user){
  • innerHTML:dojo.toJson(user)
  • 注意: 严格来说then方法的返回值并不是一个Deferred对象,它有个特定的名字"promise",即承诺,实现了一个特定的API. 你可以进一步阅读关于prommise的教程来深入学习,不过在这里,我们可以暂时理解为 一个promise对象提供了和Deferred对象完全相同的then方法。因此Deferred对象和Promise对象的then方法可以进行连续的链式调用。这样做的好处是什么呢?链式调用时,原始的Defered对象不会被修改,而且服务器端的返回的数据也没有被修改,你可以继续在original的defered对象上注册其他的回调函数来对原始数据进行进一步操作,在前面的例子基础上,你可以注册一个新的回调到original上,例如:

    original.then(function(res){
  • varuserlist=dojo.byId("userlist3");
  • });
  • 版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐


    我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
    我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
    我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
    1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
    我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
    我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
    路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
    请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
    与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
    我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
    我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
    我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
    我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
    我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
    我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
    我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
    我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
    我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
    我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
    我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时