web-dev-qa-db-ja.com

非同期関数+ await + setTimeoutの組み合わせ

私は新しい非同期機能を使用しようとしています、そして私の問題を解決することが将来他の人に役立つことを願っています。これは私が働いているコードです:

  async function asyncGenerator() {
    // other code
    while (goOn) {
      // other code
      var fileList = await listFiles(nextPageToken);
      var parents = await requestParents(fileList);
      // other code
    }
    // other code
  }

  function listFiles(token) {
    return gapi.client.drive.files.list({
      'maxResults': sizeResults,
      'pageToken': token,
      'q': query
    });
  }

問題は、私のwhileループの実行が速すぎ、スクリプトが1秒あたりに送信するリクエストがgoogle APIに送信しすぎることです。そのため、リクエストを遅らせるスリープ機能を構築したいと思います。したがって、この機能を使って他のリクエストを遅らせることもできます。リクエストを遅らせる別の方法がある場合は、教えてください。

とにかく、これは機能しない私の新しいコードです。リクエストのレスポンスは、setTimeout内の無名の非同期関数に返されますが、どのようにしてレスポンスをsleep関数に返すことができるのかわかりません。最初のasyncGenerator関数に移動します。

  async function asyncGenerator() {
    // other code
    while (goOn) {
      // other code
      var fileList = await sleep(listFiles, nextPageToken);
      var parents = await requestParents(fileList);
      // other code
    }
    // other code
  }

  function listFiles(token) {
    return gapi.client.drive.files.list({
      'maxResults': sizeResults,
      'pageToken': token,
      'q': query
    });
  }

  async function sleep(fn, par) {
    return await setTimeout(async function() {
      await fn(par);
    }, 3000, fn, par);
  }

私はすでにいくつかのオプションを試してみました。グローバル変数にレスポンスを格納してsleep関数から返す、無名関数内でのコールバックなどです。

155
JShinigami

sleepsetTimeoutされる可能性のある約束を(まだ)返していないため、await関数は機能しません。手動で確認する必要があります。

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
    await timeout(3000);
    return fn(...args);
}

ところで、ループを遅くするためには、コールバックを受けてこのように延期するsleep関数を使用したくないでしょう。私はむしろ何かのようにすることをお勧めします

while (goOn) {
  // other code
  var [parents] = await Promise.all([
      listFiles(nextPageToken).then(requestParents),
      timeout(5000)
  ]);
  // other code
}

これはparentsの計算に少なくとも5秒かかるようにします。

364
Bergi

ノード7.6 以降、utilsモジュールの関数promisifysetTimeout()と組み合わせることができます。

Node.js

const sleep = require('util').promisify(setTimeout)

ジャバスクリプト

const sleep = m => new Promise(r => setTimeout(r, m))

使用法

(async () => {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
})()

ワンライナー

await new Promise(r => setTimeout(r, 1000))
80
Harry

クイックワンライナー、インライン方式

 await new Promise(resolve => setTimeout(resolve, 1000));
33
FlavorScape

setTimeoutasync関数ではないため、ES7 async-awaitでは使用できません。しかし、ES6を使ってsleep関数を実装することができます Promise

function sleep (fn, par) {
  return new Promise((resolve) => {
    // wait 3s before calling fn(par)
    setTimeout(() => resolve(fn(par)), 3000)
  })
}

そうすれば、ES7でこの新しいsleep関数をasync-awaitで使用できるようになります。

var fileList = await sleep(listFiles, nextPageToken)

注意してください 私はES7 async/awaitをsetTimeoutと組み合わせることについてのあなたの質問に答えているだけですが、それは毎秒あまりにも多くのリクエストを送ることであなたの問題を解決するのに役立ちません。

24

setTimeoutと同じ種類の構文を使いたいのなら、このようなヘルパー関数を書くことができます。

const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
    setTimeout(() => {
        cb();
        resolve();
    }, timeout);
});

あなたはそのようにそれを呼ぶことができます:

const doStuffAsync = async () => {
    await setAsyncTimeout(() => {
        // Do stuff
    }, 1000);

    await setAsyncTimeout(() => {
        // Do more stuff
    }, 500);

    await setAsyncTimeout(() => {
        // Do even more stuff
    }, 2000);
};

doStuffAsync();

私は要旨を作った: https://Gist.github.com/DaveBitter/f44889a2a52ad16b6a5129c39444bb57

1
Dave Bitter

これは、ワンライナーでの迅速な修正です。

これが役立つことを願っています。

// WAIT FOR 200 MILISECONDS TO GET DATA //
await setTimeout(()=>{}, 200);
0
Rommy Garg

次のコードは、ChromeおよびFirefoxおよび他のブラウザで動作します。

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
    await timeout(3000);
    return fn(...args);
}

しかし、Internet Explorerでは"(resolve **=>** setTimeout..."の構文エラーが発生します

0
Shadowned