web-dev-qa-db-ja.com

angularjs $ qでプロミスを順番にチェーンするにはどうすればよいですか?

Promiseライブラリ[〜#〜] q [〜#〜]では、次のようにして、promiseを順番にチェーンできます。

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;
15
redgeoff

単に$ q.when()関数を使用します:

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

注:fooはファクトリでなければなりません。

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;
31
redgeoff

Redgeoff、あなた自身の答えは、私がを使って配列を連鎖された一連のpromiseに変換する方法です。

緊急デファクトパターンは次のとおりです。

_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は以前の非同期の結果/データであり、完全を期すために含まれています。最初のresultinitialValueです。 「結果」を渡す必要がない場合は、単に省略します。
  • 使用するpromise libに応じて$q.when(initialValue)を調整します。
  • あなたの場合、doSomethingAsyncfoo(またはfoo()が返すもの)-いずれの場合も関数です。

あなたが私のような人なら、そのパターンは一見、突き通せないクラッジのように見えますが、目が同調すると、それを古い友人と見なし始めます。

編集

以下の demo は、上記の推奨パターンが実際にdoSomethingAsync()呼び出しを順番に実行することを示すために設計されており、以下のコメントで提案されているようにチェーンを構築している間はすぐには実行されません。

36
Roamer-1888

これを持っている:

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

1行(まあ、読みやすくするために3行):

return items
    .map(item => foo.bind(null, item))
    .reduce($q.when, $q.resolve());
var when = $q.when();

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

    })(i); 
}
4
pabloRN

多分 redgeoffの答え よりも簡単な方法で、自動化する必要がない場合は、$q.when().then()と組み合わせて使用​​してプロミスをチェーンすることができます。 この投稿 の始まり。 return $q.when() .then(function(){ return promise1; }) .then(function(){ return promise2; });

4
Matthias

私はangular.bind(またはFunction.prototype.bind)を使用してpromiseを返す関数を準備し、reduceショートカットを使用してそれらをチェーンにリンクすることを好みます。例えば

// 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)
2
gleb bahmutov

正解です。しかし、私は代替案を提供すると思いました。頻繁にプロミスを連続的にチェーンしている場合は、$ q.serialに興味があるかもしれません。

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);
    });
  };
}
1
Steven Wexler