web-dev-qa-db-ja.com

ブルーバードを使用したwhileループの約束

Promiseを使用してwhileループを実装しようとしています。

ここで概説した方法はうまくいくようです。 http://blog.victorquinn.com/javascript-promise-while-loop このような関数を使用します

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
    var resolver = Promise.defer();

    var loop = function() {
        if (!condition()) return resolver.resolve();
        return Promise.cast(action())
            .then(loop)
            .catch(resolver.reject);
    };

    process.nextTick(loop);

    return resolver.promise;
};

これは、アンチパターンと、キャストや延期などの非推奨のメソッドを使用しているようです。

誰かがこれを達成するためのより良いまたはより現代的な方法を知っていますか?

ありがとう

17
Brian Keith

castresolveに変換できます。 defer実際には使用しないでください

ループを作成するには、then呼び出しを最初のPromise.resolve(undefined)にチェーンしてネストするだけです。

function promiseWhile(predicate, action, value) {
    return Promise.resolve(value).then(predicate).then(function(condition) {
        if (condition)
            return promiseWhile(predicate, action, action());
    });
}

ここでは、predicateactionの両方がpromiseを返す場合があります。同様の実装については、 promiseのループを作成する正しい方法も参照してください。 元の関数に近いのは

function promiseWhile(predicate, action) {
    function loop() {
        if (!predicate()) return;
        return Promise.resolve(action()).then(loop);
    }
    return Promise.resolve().then(loop);
}
20
Bergi

ブレークをシミュレートして続行する方が簡単なので、この実装を好みます。

var Continue = {}; // empty object serves as unique value
var again = _ => Continue;

var repeat = fn => Promise.try(fn, again)
  .then(val => val === Continue && repeat(fn) || val);

例1:送信元または宛先のいずれかがエラーを示したときに停止する

repeat(again => 
    source.read()
    .then(data => destination.write(data))
    .then(again)

例2:90%の確率でコイントスが0になった場合、ランダムに停止します

var blah = repeat(again =>
    Promise.delay(1000)
    .then(_ => console.log("Hello"))
    .then(_ => flipCoin(0.9) && again() || "blah"));

例3:合計を返す条件でループします。

repeat(again => {
  if (sum < 100) 
    return fetchValue()
      .then(val => sum += val)
      .then(again));
  else return sum;
})
3
Gorgi Kosev