37
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Promiseでwhileループを書いてみる

Last updated at Posted at 2015-09-02

io.jsのES6では標準でPromiseが使えるようになりました。Async.jsで書いてきたコードも、これからはPromiseやGenerator、coなどのコルーチンに移行していきたいです。whileループの書き方がよくわからなかったので、Stack Overflowなどで調べてみました。

リソース

以下のサイトを参考にしました。

Bluebirdの無限ループ

Bluebirdは高機能なPromiseのライブラリです。ES6 Native Promiseにはないメソッドや、コルーチンも用意されています。"Infinite" promise chains, a bad thing? #477にwhileループの例がありました。

infinite-loop-bluebird.es6
var Promise = require('bluebird');
Promise.resolve(0).then(function loop(i) {
    return new Promise(function(resolve, reject) {
        console.log(i);
        resolve(i+1);
    })
    .delay(100)
    .then(loop);
});

プログラムはio.jsの3.2.0、Bluebirdは2.9.34実行しました。

$ node -v
v3.2.0

実行結果

1秒間隔で数字がインクリメントされます。無限ループなので適当なところで止めます。

$ node infinite-loop-bluebird.es6
0
1
2
3
...

Promise.delay()を先に書くこともできます。

var Promise = require('bluebird');
Promise.resolve(0).then(function loop(i) {
    return Promise.delay(100).then(function() {
        console.log(i);
        return i+1;
    })
    .then(loop);
});

ES6 Native Promiseの無限ループ

上記をES6 Native Promiseに書き換えてみます。ES6ネイティブにはBluebirdのdelayや、QのdelayがないのでsetTimeoutで代用します。

infinite-loop-native.es6
Promise.resolve(0).then(function loop(i) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(i);
            resolve(i+1);
        }, 100);
    })
    .then(loop);
});

実行結果

Bluebirdの結果と同じです。

$ node infinite-loop-native.es6
0
1
2
3
...

ES6 Native Promiseのwhile ループ

While loop with promisesにあるのは、Qの例ですがES6 Native Promiseに書き換えてみました。

while-loop-native
function action(i) {
    console.log(i);
    return {
        done: i > 9,
        value: i+1
    };
}

function loop(promise, fn) {
    return promise.then(fn).then(function(wrapper) {
        return !wrapper.done ? loop(Promise.resolve(wrapper.value), fn): wrapper.value;
    });
}

loop(Promise.resolve(0), action).then(function(value) {console.log('end: ' + value)});

実行結果

数字がインクリメントされ、i > 9がtrueになるとループが停止します。

$ node while-loop-native.es6

0
1
2
3
4
5
6
7
8
9
10
end: 11

Bluebirdのwhile ループ

Memory leak trying to create a while loop with promises #502に再帰を使ったシンプルなループの例がありました。

just-recursion.es6
var Promise = require('bluebird');
(function loop(i) {
  if (i < 10) {
    return Promise.delay(100).then(function() {
      console.log(i);
      return i+1;
    }).then(loop);
  }
  return Promise.resolve(i);
})(0);

実行結果

$ node just-recursion.es6

0
1
2
3
4
5
6
7
8
9
10

もうひとつはBluebirdのPromise.coroutineを使う例です。ジェネレーターの中でwhileループを書きます。

coroutine-loop.es6
var Promise = require('bluebird');

function condition(i) {
    return i > 10;
}

function action(i) {
    console.log(i);
    return Promise.resolve(i+1);
}

var loop = Promise.coroutine(function* (condition, action, value) {
    while(!condition(value)) {
        value = yield action(value);
        yield Promise.delay(100);
    }
});

loop(condition, action, 0);

実行結果

$ node coroutine-loop.es6

0
1
2
3
4
5
6
7
8
9
10
37
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?