1. ホーム
  2. javascript

[解決済み] プロミスのループの正しい書き方。

2022-08-17 03:32:49

質問

次のようなループを正しく構築するにはどうしたらよいでしょうか。 プロミスコール と連鎖した logger.log(res) はイテレーションを通して同期的に実行されますか?(ブルーバード)

db.getUser(email).then(function(res) { logger.log(res); }); // this is a promise

以下の方法で試してみました。 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;
});

var count = 0;
promiseWhile(function() {
    return count < 10;
}, function() {
    return new Promise(function(resolve, reject) {
        db.getUser(email)
          .then(function(res) { 
              logger.log(res); 
              count++;
              resolve();
          });
    }); 
}).then(function() {
    console.log('all done');
}); 

一応動作しているようですが、呼び出す順番が保証されていないような気がします。 logger.log(res)を呼び出します。

何か提案はありますか?

どのように解決するのですか?

<ブロッククオート

logger.log(res)の呼び出し順を保証していないようです。

実はそうなんです。その文は resolve の呼び出しの前に実行されます。

何か提案はありますか?

たくさんあります。最も重要なのは、あなたが使っている create-promise-manually アンチパターン - だけを行う

promiseWhile(…, function() {
    return db.getUser(email)
             .then(function(res) { 
                 logger.log(res); 
                 count++;
             });
})…

次に、その while 関数はかなり簡略化できるはずです。

var promiseWhile = Promise.method(function(condition, action) {
    if (!condition()) return;
    return action().then(promiseWhile.bind(null, condition, action));
});

第三に、私なら while ループ (クロージャ変数を含む) ではなく for ループになります。

var promiseFor = Promise.method(function(condition, action, value) {
    if (!condition(value)) return value;
    return action(value).then(promiseFor.bind(null, condition, action));
});

promiseFor(function(count) {
    return count < 10;
}, function(count) {
    return db.getUser(email)
             .then(function(res) { 
                 logger.log(res); 
                 return ++count;
             });
}, 0).then(console.log.bind(console, 'all done'));