JQuery Отложенный с помощью набора функций

У меня есть объект, полный таких функций:

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

Все ключи объекта привязаны внутри массива следующим образом:

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

Я использовал массив для выполнения всех функций:

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

Моя проблема в том, что мне нужно каким-то образом отложить выполнение всех функций, чтобы:

  • В цикле $.each функции запускаются серийно
  • Некоторый способ отложить выполнение последующего кода до тех пор, пока все функции в массиве/объекте не будут завершены.

Я читал, что для этого я должен использовать метод $.map, но мне сложно с этим справиться.

Ответ 1

Ничего себе... это было упражнение - $. Отложенное() было немного трудно уловить мой разум, но я все это работал так, как хотел! Я не знаю, как это упростило - возможно, другие могут сделать его более эффективным.

Суть его в том, чтобы создать цепочку отложенных слов с помощью .pipe().

EDIT: Мой код (ниже) не вмещает менее 2 объектов в список ссылочных ключей. Я обновил jsfiddle для работы с ключевыми списками любого размера.


Вы можете увидеть все следующие работы JSFiddle здесь: http://jsfiddle.net/hBAsp/3/


Вот шаг за шагом, как я его решил:

  • Начните с объекта, полного функций и массива ссылочных ключей (в том порядке, в котором вы их обрабатывали). Функции должны ожидать получения отложенного объекта для разрешения при завершении:

    var obj = {
        one: function(dfd){
            /* do stuff */
            dfd.resolve();
        },
        two: function(dfd){...},
        three: function(dfd){...},
        etc...
    };
    var keys=['one','two','three', etc...];`
    
  • Создайте основную отложенную оболочку, передающую обещание в функцию инициализации. Мы добавим код в функцию, когда мы идем:

    var mainDeferred = $.Deferred(function(mainDFD){
    
  • Внутри этой функции инициализации создайте массив отложенных событий, вручную создав первый отложенный объект:

    var dfds = [$.Deferred()];
    
  • Далее, используйте цикл for, чтобы пройти через второй через следующие пункты в нашем списке ключей. Мы будем:

    • создание отложенного объекта для каждого элемента, который мы выполняем
    • настройка анонимной функции, которая будет запускать связанную с ключом функцию из нашего obj, передавая ее для разрешения нашего недавно созданного объекта Отложенные
    • создание новой созданной функции на ранее созданном объекте "Отложенный" (поэтому мы должны были создать первый вручную).
    • Вы должны использовать замкнутый цикл в списке для того, чтобы преодолеть проблемы, связанные с 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);
      };
      
  • Вручную создайте последнюю анонимную функцию и переместите ее на следующий отложенный объект в нашем списке. Мы делаем это вручную, потому что хотим передать ему главный отложенный объект для разрешения, чтобы весь shebang выстрелил как можно скорее, как только завершился последний процесс:

    dfds[keys.length-2].pipe(function(){
        obj[keys[keys.length-1]].call(this,mainDFD);
    });
    
  • Теперь, когда весь наш конвейер построен, все, что нам нужно сделать, - это отключить первый объект и назначить ему первый отложенный для разрешения:

    obj[keys[0]].call(this,dfds[0]);
    
  • Просто закройте нашу основную функцию отсроченной инициализации (все это будет срабатывать, как только будет создано отложенное:

    });
    
  • Теперь мы также можем подключить функцию к основному объекту, который будет запущен после запуска всех предыдущих элементов:

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

Ответ 2

Я думаю, вы можете использовать pipe, чтобы передать функцию обратного вызова в виде массива. Вот пример .

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"

Вы можете изменить результат "разрешить" на "отклонение" в функциях проверки, если вы хотите увидеть другой результат. например: Если вы меняете 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]);
}

Примечание. Вы должны убедиться, что обратный вызов всегда возвращает объект "Отложенные".