如何使用dojo优雅地构造一系列请求/回调?

时间:2012-06-27 00:47:13

标签: javascript ajax dojo deferred

我已经使用了dojo,但并不完全关注dojo.Deferred(或者至少我没有使用所有可用的功能)。我一直在做一些关于它的阅读,并想知道以下场景是否适合将Deferred用作更优雅的方法?或者如果不延迟,是Promise还是在dojo中可用的其他类型的链接技术可以以更易读/顺序的方式实现以下目的?

var _this = this;

var secondCallback =  function( res ) {
    console.debug('All is complete Result [' + res +']');
};

var firstCallback = function( res ) {
    if(res == 'true') 
        my.lib.processRPC( my.rpc.module.DoSecondStep( _this.user_id ), secondCallback );
};

my.lib.processRPC( my.rpc.module.CheckFirstStep(), firstCallback );

如果是这样,这看起来怎么样? Deferred如何在这里使用?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

我用一个简单的window.setTimeout来愚弄您的RPC模块,以便在网络延迟后模拟异步回调,并用_this_user_id替换_this.user_id,以及可能的其他调整。

可运行的示例:http://dojo-sandbox.net/public/4c296/0

/* In resopnse to http://stackoverflow.com/questions/11217904/how-to-elegantly-structure-a-chain-of-requests-callbacks-using-dojo */
require([
  "dojo/_base/Deferred"
], function(Deferred) {

  var my_lib = function() {};
  my_lib.processRPC = function(value, def) {
    // simulate a long lived network call or whatever
    window.setTimeout(function() {
      console.log("rpc  has fired");
      def.resolve(value);
    }, 1000);
  }


  var my_rpc_module = function() {};
  my_rpc_module.CheckFirstStep = function() {
    console.log("CheckFirstStep here.");
    return 'true';
  }
  my_rpc_module.DoSecondStep = function(userid) {
    console.log("CheckSecondStep here for userid " +userid + ".");
    return 'finished';
  }

  var _this_user_id = "Mr Blobby";

  var secondCallback = new Deferred();

  secondCallback.then(function(res) {
    console.debug('All is complete Result [' + res +']');
  });

  var firstCallback = new Deferred();
  firstCallback.then(function( res ) {
    if(res == 'true') {
        my_lib.processRPC( my_rpc_module.DoSecondStep( _this_user_id ), secondCallback );
    }
  });


  my_lib.processRPC( my_rpc_module.CheckFirstStep(), firstCallback );

})

答案 1 :(得分:0)

my.lib.processRPC需要返回Promise进行处理。 "Deferred"是拒绝/履行承诺的接口,您可能不想导出这些方法 - 您只需从私有范围的Deferred返回Promise,可以在其上安装回调。

我不是Dojo专家,您可能需要根据确切的语法调整以下代码。一个接近你的场景的实现 - 我希望my.rpc.module.DoSecondStep( _this.user_id )只是一个创建选项对象的函数 - 看起来像这样:

my.lib.processRPC = function(options)
    var d = new Deferred();
    // ...
    return d.getPromise();
    // do some heavy and/or asynchronous processing and call
    d.resolve(result) // somewhen in the future
};

// narrative code:
my.lib.processRPC( my.rpc.module.getFirstStep() ).then(function(result) {
    if (result)
        return my.lib.processRPC( my.rpc.module.getSecondStep( _this.user_id ) )
          .then( function( res ) {
            console.debug('All is complete Result [' + res +']');
          });
     else
        return /* false */ result;
}).addCallback(console.log.bind(console, "everything finished"));

但我建议doStepX函数真的应该自己处理。所以他们应该返回Deferreds / Promises(最终通过内部调用processRPC),并在它们不成功时拒绝它们。延期将“冒泡”这样的错误。

my.rpc.module.doFirstStep = function() {
    var d = new Deferred();
    // ...
    return d.getPromise();
    // do some heavy and/or asynchronous processing and call
    d.resolve(result) // or
    d.reject(error) // somewhen in the future
};
my.rpc.module.doSecondStep = function(id) {
    // returning a Promise, as above
};

// really narrative code:
my.rpc.module.doFirstStep()
  .then(my.rpc.module.doSecondStep)
  .addCallbacks(function( res ) {
    console.log('All is complete Result [' + res +']');
  }, function (err) {
    console.log('Something happened: [' + err +']');
  });

请注意doSecondStep接收第一个延迟的(成功)结果作为参数。如果您不想要或不需要在不调用的情况下指定其他参数,则需要使用类似.bind()或包装函数的内容:

...then(function firstCallback() {
    return my.rpc.module.DoSecondStep( _this.user_id );
})...