链jQuery承诺

时间:2012-11-12 18:16:27

标签: jquery asynchronous eval promise

我试图将承诺链接起来,而不是管道,只是链接。

例如,我有这个方法:

var execute = function(x){
   // this could be an AJAX call
   var d= $.Deferred();

    console.log('Begin ' + x);

    setTimeout(function(){
       console.log('End ' + x);            
       d.resolve();
    },500);

    return d;
};

我想多次执行此方法,但是一个接一个地执行。我创建了一个方法,而不是使用eval,但我对使用eval感到不满意:

var executeTimes = function(r){
    var s = '';
    for(var i=0;i<r;i++){
        s = s + 'execute('+i+')';
        if(i!==r-1)
        s = s + '.then(function(){';
    }

    for(var i=0;i<r-1;i++){
        s= s+'})';
    }

    eval(s);
}

我的想法是,executeTimes(3);你得到这个输出:

Begin 0 
End 0 
Begin 1 
End 1 
Begin 2 
End 2 

我在这里创建了一个实例:http://jsfiddle.net/vtortola/Cfe5s/

什么是最好的解决方案?

干杯。

2 个答案:

答案 0 :(得分:4)

递归看起来很整洁:http://jsfiddle.net/Cfe5s/3/

var executeTimes = function(r) {
  (function recurse(i) {
    execute(i).then(function() {
      if(i + 1 < r) {
        recurse(i + 1);
      }
    });
  })(0);
};

你启动一个用execute运行0的函数,当它完成时你重新开始(通过递归),但这次是1。在递归之前,您必须检查是否继续:只有当递增的值仍然低于r时才这样做。

答案 1 :(得分:2)

我的方法类似于你的方法,但我没有连接字符串,而是嵌套函数调用:P

var executeTimes = function(r){   
    // The last (inner-most) step does nothing. 
    // just in the case we pass r <= 0
    var f = function(){}; 

    for(;  r > 0 ; --r){
        // Create closure with call to execute( ... ).then( ... )
        f = (function(_f, _r){
            return function(){ execute(_r).then(_f); }; 
        })(f, r - 1);
    }
    return f;
}

它返回一个行为符合你想要的函数。如果你这样做:

executeTimes​(3)()​​

这会产生与您的示例相同的输出。 可以轻松地调整此示例以支持任何函数和任何最后一步(我假设函数toExec想要接收调用的“数字”):

var executeTimes2 = function(toExec /*a function*/, 
                            steps /*a number*/, 
                            finalStep /*a function*/)
{   
    // The last (inner-most) step.
    // just in the case we pass r <= 0
    var f = finalStep? finalStep : function(){}; 

    for(;  steps > 0 ; --steps){
        // Create closure with call to execute( ... ).then( ... )
        f = (function(_f, _r){
            return function(){ toExec(_r).then(_f); }; 
        })(f, steps - 1);
    }
    return f;
}

所以你的函数可以这样调用3次:

executeTimes2(execute, 3)()