jQuery 延迟使用一系列函数

jQuery Deferred with an array of functions

本文关键字:一系列 函数 延迟 jQuery      更新时间:2023-09-26

我有一个充满函数的对象,如下所示:

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. 某种方法,用于将后续代码的运行推迟到数组/对象中的所有函数完成后。

我已经读到我应该为此使用 $.map 方法,但我很难理解它。

哇...那是一个练习——$。Deferred() 有点难以让我的思想被包裹起来,但我让一切都按照我想要的方式工作!我不知道这有多精简——也许其他人可以提高效率。

它的要点是使用 .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. 在该初始化函数中,创建一个延迟数组,手动创建第一个延迟对象:

    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. 现在我们还可以通过管道将函数传送到 main 对象,以便在我们之前的所有元素都运行后运行:

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

我认为您可以使用管道将回调函数作为数组进行管道传输。下面是一个示例。

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"

如果您想查看不同的结果,可以在检查函数中将结果"解析"更改为"拒绝"。 例如:如果将检查 A 更改为拒绝。

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

输出将是

"checkA"
"checkAll fail"

它不会去检查B和检查C,因为检查A被拒绝了。以便您可以使用数组调用函数

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

注意。必须确保回调始终返回延迟对象。