Kombinacja funkcji async + wait + setTimeout

Próbuję korzystać z nowych funkcji asynchronicznych i mam nadzieję, że rozwiązanie mojego problemu pomoże innym w przyszłości. To jest mój kod, który działa:

  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
    });
  }

Problem polega na tym, że moja pętla while działa zbyt szybko i skrypt wysyła zbyt wiele żądań na sekundę do google API. Dlatego chciałbym zbudować funkcję snu, która opóźnia żądanie. Mógłbym więc użyć tej funkcji również do opóźniania innych żądań. Jeśli istnieje inny sposób na opóźnienie żądania, proszę pozwolić mi wiedzieć.

W każdym razie, to jest mój nowy kod, który nie działa. Odpowiedź żądania jest zwracana do anonimowej funkcji asynchronicznej w setTimeout, ale po prostu nie wiem, w jaki sposób mogę zwrócić odpowiedź na funkcję sleep resp. do początkowej funkcji asynchronicznego generatora.

  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);
  }

Wypróbowałem już kilka opcji: zapisanie odpowiedzi w zmiennej globalnej i zwrócenie jej z funkcji sleep, wywołanie zwrotne w funkcji anonimowej itp.

Author: Felix Kling, 2015-10-22

4 answers

Twoja sleep funkcja nie działa, ponieważ setTimeout nie działa (jeszcze?) zwróć obietnicę, która może być awaited. Musisz to obiecać ręcznie:

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

Btw, aby spowolnić pętlę, prawdopodobnie nie chcesz używać funkcji sleep, która przyjmuje callback i odkłada go w ten sposób. Raczej polecam zrobić coś takiego

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

Co pozwala obliczyć parents zająć co najmniej 5 sekund.

 253
Author: Bergi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 00:26:46

od węzła 7.6 można łączyć funkcje promisify z modułu utils z setTimeout().

Węzeł.js

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

Javascript

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

Użycie

async function main() {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
}

main()
 31
Author: Harry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-21 19:57:11

setTimeout nie jest funkcją async, więc nie można jej używać z ES7 async-wait. Ale możesz zaimplementować swoją sleep funkcję używając ES6 Promise :

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

Wtedy będziesz mógł użyć tej nowej funkcji sleep z ES7 async-wait:

var fileList = await sleep(listFiles, nextPageToken)

Proszę zauważyć , że odpowiadam tylko na pytanie dotyczące połączenia ES7 async / wait z setTimeout, chociaż może to nie pomóc rozwiązać problemu z wysyłaniem zbyt wielu żądań na sekundę.

 16
Author: Leonid Beschastny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-13 21:57:09

Szybka jednowierszowa, inline way

 await new Promise((resolve) => setTimeout(() => resolve(), 1000));
 0
Author: FlavorScape,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-27 21:22:30