Jquery Deferred и несколько отложенных в цепочке

Помогите, пожалуйста:

Например, у меня есть 20 тайм-аутов, созданных с помощью window.setTimeout, и я хочу, чтобы они запускались один за другим:

тайм-аут вызова 1 => после тайм-аута завершения вызова 2 => после тайм-аута завершения вызова 3 и так далее.

Вообще есть массив функций и количество таймаутов не фиксировано.

моя функция с отложенным:

function someFunction(index) {
   console.log("someFunction called, index = " + index);
   var $deferred = $.Deferred();

   window.setTimeout(function () {
       $deferred.resolve();
   }, 2000);

   return $deferred.promise();
}

для цикла:

var $deferred;
$(someArray).each(function (index) {
    if (!$deferred) {
        $deferred = someFunction(index);
    } else {
        $deferred.then(function () {
            return someFunction(index);
        });
    }
});

все остальные запускаются сразу без в цепочке


person Алексей Поликар&    schedule 13.11.2015    source источник
comment
какая польза от переменной someArray?   -  person dunli    schedule 13.11.2015


Ответы (3)


Если вы хотите связать их один за другим, вам нужно будет сделать это:

var $deferred;
$(someArray).each(function (index) {
    if (!$deferred) {
        $deferred = someFunction(index);
    } else {
        $deferred = $deferred.then(function () {
            return someFunction(index);
        });
    }
});

Что вы делали, так это помещали все обработчики .then() в один и тот же отложенный, который будет запускать их все параллельно, а не последовательно. Вам нужен эквивалент p.then(...).then(...).then(...). Поскольку каждый .then() возвращает новое обещание, вам нужно перейти к следующему звену в цепочке.


Вы можете найти этот шаблон проектирования немного проще для последовательного перебора массива с асинхронной операцией, которая генерирует обещание:

someArray.reduce(function(p, item) {
    return p.then(function() {
        return someFunction(item);
    });
}, $.Deferred().resolve()).then(function() {
    // all done here
});

Рабочая демонстрация: http://jsfiddle.net/jfriend00/uusjs3mt/

person jfriend00    schedule 13.11.2015
comment
setTimeout продолжительность не применяется, как ожидалось, в .reduce() версии - person guest271314; 13.11.2015
comment
Да, была версия 1.7.2 на console jsfiddle.net/59sn1u31; 1.11.0 jsfiddle.net/59sn1u31/1 - person guest271314; 13.11.2015
comment
Да, пробовал на .reduce() версии на console, ТАК использует 1.7.1; см. также stackoverflow.com/questions /32790917/ - person guest271314; 13.11.2015
comment
@guest271314 - Вы публикуете загадочные комментарии, которых я не понимаю. Если вам нужна помощь, пожалуйста, используйте слова, чтобы описать, о чем вы спрашиваете или с чем еще вам нужна помощь. - person jfriend00; 13.11.2015
comment
@guest271314 guest271314 - если вы хотите использовать надежные и предсказуемые обещания, я бы посоветовал только последнюю версию jQuery, браузер, поддерживающий обещания ES6, или библиотеку Promise, такую ​​как Bluebird. - person jfriend00; 13.11.2015
comment
Попытка сообщить, что .reduce() версия вашего поста не дала ожидаемого результата после попытки console . Затем подумал, что SO использует версию 1.7.1 jQuery, которая возвращает результаты, отличные от версии 1.8+. Ваши js части возвращают значения, которые ожидаются в jQuery версии 1.8+. - person guest271314; 13.11.2015
comment
@guest271314 - Хорошо, теперь я понимаю, о чем ты говоришь. Вы настроены с тем, что в ответе сейчас? Или есть еще вопросы по этому поводу? - person jfriend00; 13.11.2015
comment
Да . Один вопрос: при попытке использовать метод .reduce(), какой подход является подходящим для накопления возвращаемых значений выполненных, отклоненных обещаний, которые будут доступны в .then() после .reduce()? - person guest271314; 13.11.2015
comment
@ guest271314 - Есть несколько вариантов накопления результатов в зависимости от того, что вы пытаетесь сделать и какой результат вы хотите получить. Это потребует более сложного ответа. Я предлагаю вам задать отдельный вопрос, где это можно было бы решить. - person jfriend00; 13.11.2015
comment
@jfriend00 stackoverflow.com/questions/33688342/ - person guest271314; 13.11.2015

Попробуйте использовать $.queue() , $.dequeue() , $.map()

function someFunction(index) {
  console.log("someFunction called, index = " + index);
  var $deferred = $.Deferred();

  window.setTimeout(function() {
    $deferred.resolve();
  }, 2000);

  return $deferred.promise();
}

var someArray = [1, 2, 3, 4, 5];

$.queue(someArray, "dfd", $.map(someArray, function(value, index) {
  return function(next) {
    someFunction(index).then(next)
  }
}));
$.dequeue(someArray, "dfd");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

person guest271314    schedule 13.11.2015

Оба метода работают:

$.queue(someArray, "dfd", $.map(someArray, function(value, index) {
  return function(next) {
    someFunction(index).then(next)
  }
}));
$.dequeue(someArray, "dfd");

а также

someArray.reduce(function(p, item) {
    return p.then(function() {
        return someFunction(item);
    });
}, $.Deferred().resolve()).then(function() {
    // all done here
});
person Алексей Поликар&    schedule 13.11.2015
comment
Протокол здесь, в StackOverflow, заключается в том, чтобы не публиковать свой собственный ответ, который просто дублирует информацию, опубликованную другими. Если на ваш вопрос был дан ответ, вы можете выбрать лучший ответ, щелкнув зеленую галочку слева от этого ответа, и вы можете прокомментировать любой ответ. Как только вы заработаете больше очков репутации, вы сможете проголосовать за любой ответ, который вам помог. - person jfriend00; 13.11.2015