jQuery延迟了一系列函数

时间:2012-08-06 18:29:41

标签: javascript jquery asynchronous jquery-deferred sequential

我有一个充满这样功能的对象:

var functions = {
    fun1 : function(){ ... }
    fun2 : function(){ ... }
    fun3 : function(){ ... }
};

对象键都在数组中引用,如下所示:

var funList = ['fun1','fun2','fun3'];

我一直在使用该数组来运行所有函数:

$.each(funList, function(i,v){
    functions[v].call(this, args);
});

我的问题是,我需要一些方法来推迟所有功能的运行:

  1. 在$ .each循环中,函数以串行方式运行
  2. 在数组/对象中的所有函数完成之后,推迟后续代码运行的一些方法。
  3. 我已经读过我应该使用$ .map方法,但是我很难把它包围起来。

2 个答案:

答案 0 :(得分:8)

哇...这是一个练习 - $。延期()有点难以让我的思绪缠身,但我把它全部都搞定了我想要的!我不知道这是多么精简 - 或许其他人可以提高效率。

它的要点是使用.pipe()创建一个延迟链。

编辑:我的代码(下方)在参考密钥列表中不包含少于2个对象。我更新了jsfiddle以使用任何大小的密钥列表。


您可以在此处查看有关JSFiddle的所有工作:http://jsfiddle.net/hBAsp/3/


以下是我如何解决它的一步一步:

  1. 从一个充满函数的对象和一组引用键开始(按照您希望它们处理的顺序)。函数应该期望在完成时接收要解析的延迟对象:

    var obj = {
        one: function(dfd){
            /* do stuff */
            dfd.resolve();
        },
        two: function(dfd){...},
        three: function(dfd){...},
        etc...
    };
    var keys=['one','two','three', etc...];`
    
  2. 创建主延迟包装器,将promise传递给初始化函数。我们将把代码添加到函数中:

    var mainDeferred = $.Deferred(function(mainDFD){
    
  3. 在初始化函数内部,创建一个deferred数组,手动创建第一个延迟对象:

    var dfds = [$.Deferred()];
    
  4. 接下来,使用for循环遍历第二个到我们的键列表中的倒数第二个项目。我们将:

    1. 为我们单步执行的每个项目创建一个延迟对象
    2. 设置一个匿名函数,它将从我们的obj运行与键相关的函数,传递给它来解析我们新创建的Deferred对象
    3. 将新创建的函数传递到先前创建的Deferred对象上(这就是我们必须手动创建第一个的原因)
    4. 您必须在for列表中使用一个封闭的循环来解决JavaScript范围界定问题

      for (i=1; i<keys.length-1; i++){
          (function(n){
              dfds.push($.Deferred());
              dfds[i-1].pipe(function(){
                  obj[keys[n]].call(this,dfds[n]);
              });
          })(n);
      };
      
  5. 手动创建最后一个匿名函数并将其传递到列表中倒数第二个延迟对象。我们手动完成这个操作,因为我们想要传递给它的主要延迟对象以便解决,以便整个shebang在最后一个进程运行后立即激活:

    dfds[keys.length-2].pipe(function(){
        obj[keys[keys.length-1]].call(this,mainDFD);
    });
    
  6. 既然我们已经构建了整个管道,我们所要做的就是触发第一个对象并为其分配第一个延迟解决方案:

    obj[keys[0]].call(this,dfds[0]);
    
  7. 只需关闭我们的主延迟初始化函数(这将在创建延迟时立即触发:

    });
    
  8. 现在我们还可以将一个函数传递给主对象,以便在我们之前的所有元素都运行后运行:

    mainDeferred.pipe(function(){
        /* do other stuff */    
    });
    

答案 1 :(得分:1)

我认为您可以使用pipe将回调函数作为数组进行管道传输。这是一个example

var a = $.Deferred();

var b = $.Deferred();

var c = $.Deferred();

var checkA = function() {
  console.log('checkA');
  return a.resolve();
};


var checkB = function() {
  console.log('checkB');
  return b.resolve();
};

var checkC = function() {
  console.log('checkC');
  return c.reject();
};

checkAll = $.Deferred().resolve().promise();
checkAll = checkAll.pipe(checkA);
checkAll = checkAll.pipe(checkB);
checkAll = checkAll.pipe(checkC);

checkAll.done(function() {
  return console.log('checkAll done');
}).fail(function() {
  return console.log('checkAll fail');
});

输出将是

"checkA"
"checkB"
"checkC"
"checkAll fail"

如果要查看不同的结果,可以在检查功能中将结果“resolve”更改为“reject”。例如:如果您将checkA更改为拒绝。

var checkA = function() {
  console.log('checkA');
  return a.reject();
};

输出

"checkA"
"checkAll fail"

它不会去checkB和checkC因为checkA被拒绝了。 这样你就可以用数组调用函数

funList = [checkA, checkB, checkC];
for(var i=0; i<funList.length; i++){
  checkAll = checkAll.pipe(funList[i]);
}

请注意。 您必须确保回调始终返回Deferred对象。