web-dev-qa-db-ja.com

ES6 promiseを返すsetTimeoutのバージョンはありますか?

この質問 に似ていますが、一般的に約束がどのように機能するかを尋ねるのではなく、具体的に知りたいです:

promise を返すものに setTimeout をラップする標準/最良の方法は何ですか?私はAngularのようなものを考えています $timeout function 、ただしAngular specific。

35
Michael Kropat

ブラウザで

まず第一に、これのためのビルトインはありません。 ES2015を強化する多くのライブラリは、ブルーバードの鞭のようなものを約束します。

他の答えは、関数の実行と遅延を抑制し、キャンセルできないタイムアウトも作成すると思います。私は単にそれを次のように書くでしょう:

function delay(ms){
    var ctr, rej, p = new Promise(function (resolve, reject) {
        ctr = setTimeout(resolve, ms);
        rej = reject;
    });
    p.cancel = function(){ clearTimeout(ctr); rej(Error("Cancelled"))};
    return p; 
}

その後、次のことができます。

delay(1000).then(/* ... do whatever */);

または

 doSomething().then(function(){ return delay(1000); }).then(doSomethingElse);

ES2015の基本機能のみが必要な場合は、次のようにさらに簡単になります。

let delay = ms => new Promise(r => setTimeout(r, ms));

ノード内

setTimeoututil.promisifyを使用してdelay関数を取得できます。つまり、new Promiseコンストラクターを使用する必要はありません。

48

実装方法は次のとおりです。

function delay(duration, func) {
  var args = Array.prototype.slice.call(arguments, 2);

  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(func.apply(null, args));
    }, duration);
  });
}

(ES5構文は意図的に選択されています)

しかし、すでにこれを実行している共通ライブラリ、またはそれを実行するより良い方法があるかもしれません。

4
Michael Kropat

clearTimeoutと同様に、約束されたタイムアウトの適切なキャンセルが必要な場合-setTimeoutから直接promiseを返すのは便利ではありません。 。特に、try...finallyブロックで ES7 async/await を使用する場合。タイムアウト操作用に別の変数を用意することをお勧めします。このアプローチを小さな await-timeout パッケージとして実装しました。次のように機能します。

import Timeout from 'await-timeout';

async function foo() {
  const timeout = new Timeout();
  try {
    const fetchPromise = fetch('https://example.com');
    const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
    await Promise.race([fetchPromise, timerPromise]);
  } finally {
    timeout.clear();
  }
}

この例では、フェッチが成功した場合やエラーが発生した場合にタイムアウトが確実にクリアされ、console.log('Timeout!')は呼び出されません。

1
vitalets