Подтвердить что ты не робот

Как последовательно цепочка promises с угловыми $q?

В библиотеке обещаний Q вы можете последовательно выполнить цепочку promises:

var items = ['one', 'two', 'three'];
var chain = Q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;

однако с $q не работает следующее:

var items = ['one', 'two', 'three'];
var chain = $q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;
4b9b3361

Ответ 1

Просто используйте функцию $q.when():

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;

Примечание: foo должен быть factory, например

function setTimeoutPromise(ms) {
  var defer = $q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el, i) {
  chain = chain.then(foo(el, (items.length - i)*1000));
});
return chain;

Ответ 2

Redgeoff, ваш собственный ответ - это то, как я использовал для перевода массива в цепочку с цепочкой promises.

Возникающий де-факто шаблон выглядит следующим образом:

function doAsyncSeries(arr) {
    return arr.reduce(function (promise, item) {
      return promise.then(function(result) {
        return doSomethingAsync(result, item);
      });
    }, $q.when(initialValue));
}

//then
var items = ['x', 'y', 'z'];
doAsyncSeries(items).then(...);

Примечания:

  • .reduce - это необработанный javascript, а не часть библиотеки.
  • result - это предыдущий асинхронный результат/данные и включен для полноты. Начальный result равен initialValue. Если нет необходимости передавать результат, то просто оставьте его.
  • адаптировать $q.when(initialValue) в зависимости от того, какой обезьян вы используете.
  • в вашем случае doSomethingAsync есть foo (или что возвращает foo()?) - в любом случае, функция.

Если вы похожи на меня, тогда картина будет выглядеть с первого взгляда, как непроницаемая кладка, но как только ваш глаз будет настроен, вы начнете рассматривать его как старого друга.

Edit

Здесь демонстрация, предназначенная для демонстрации того, что шаблон, рекомендованный выше, фактически выполняет свои вызовы doSomethingAsync() последовательно, а не сразу при построении цепочки, как предложено в комментарии ниже.

Ответ 3

Я предпочитаю готовить функции, которые возвращают promises с помощью angular.bind (или Function.prototype.bind), а затем связывают их с цепочкой с помощью сокращения ярлыка. Например

// getNumber resolves with given number
var get2 = getNumber.bind(null, 2);
var get3 = getNumber.bind(null, 3);
[get2, get3].reduce(function (chain, fn) {
   return chain.then(fn);
}, $q.when())
.then(function (value) {
   console.log('chain value =', value);
}).done();
// prints 3 (the last value)

Ответ 4

Ваш ответ верный. Однако я подумал, что я бы предложил альтернативу. Вы можете быть заинтересованы в $q.serial, если вы часто зацикливаетесь на цепочке promises.

var items = ['one', 'two', 'three'];
var tasks = items.map(function (el) {
  return function () { foo(el, (items.length - i)*1000)); });
});

$q.serial(tasks);

function setTimeoutPromise(ms) {
  var defer = $q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

Ответ 5

Пожалуй, проще, чем ответ redgeoff, если вам не нужно автоматизировать, вы можете связать promises с помощью $q.when() в сочетании с .then() как показано в начале этот пост. return $q.when() .then(function(){ return promise1; }) .then(function(){ return promise2; });

Ответ 6

Измените это:

var items = ['one', 'two', 'three'];

:

var items = [
  foo.bind(null, 'one'),
  foo.bind(null, 'two'),
  foo.bind(null, 'three')
];

Затем одна строка:

return items.reduce($q.when, $q.resolve());

Ответ 7

var when = $q.when();

for(var i = 0; i < 10; i++){
    (function() {
         chain = when.then(function() {
        return $http.get('/data');
      });

    })(i); 
}