Подтвердить что ты не робот

Комбинация асинхронной функции + ожидание + setTimeout

Я пытаюсь использовать новые функции async, и я надеюсь, что решение моей проблемы поможет другим в будущем. Это мой код, который работает:

  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 работает слишком быстро, и скрипт отправляет слишком много запросов в секунду в API Google. Поэтому я хотел бы построить функцию сна, которая задерживает запрос. Таким образом, я мог бы также использовать эту функцию для задержки других запросов. Если есть другой способ отсрочить запрос, пожалуйста, дайте мне знать.

Во всяком случае, это мой новый код, который не работает. Ответ запроса возвращается анонимной асинхронной функции в setTimeout, но я просто не знаю, как я могу вернуть ответ на функцию сна resp. к исходной функции асинхронного генератора.

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

Я уже пробовал некоторые варианты: сохранение ответа в глобальной переменной и возврат его из функции сна, обратный вызов в анонимной функции и т.д.

4b9b3361

Ответ 1

Ваша функция sleep не работает, потому что setTimeout не (пока?) возвращает обещание, которое может быть await ed. Вам нужно будет прокоментировать его вручную:

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

Btw, чтобы замедлить цикл, вы, вероятно, не хотите использовать функцию sleep, которая выполняет обратный вызов и откладывает его так. Я бы рекомендовал сделать что-то вроде

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

который позволяет вычислять parents как минимум 5 секунд.

Ответ 2

Начиная с узла 7.6, вы можете комбинировать функцию promisify функций из модуля utils с setTimeout().

Node.js

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

Javascript

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

использование

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

Ответ 3

Быстрый однострочный, встроенный способ

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

Ответ 4

setTimeout не является функцией async, поэтому его нельзя использовать с ES7 async-await. Но вы могли бы реализовать свою функцию sleep, используя ES6 Promise:

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

Затем вы сможете использовать эту новую функцию sleep с ES7 async-await:

var fileList = await sleep(listFiles, nextPageToken)

Обратите внимание,, что я отвечаю только на ваш вопрос о комбинировании ES7 async/await с setTimeout, хотя это может не помочь решить вашу проблему с отправкой слишком большого количества запросов в секунду.


Обновление: Современные версии node.js имеют встроенную реализацию асинхронного тайм-аута, доступную через util.promisify помощник:

const {promisify} = require('util');
const setTimeoutAsync = promisify(setTimeout);

Ответ 5

Если вы хотите использовать тот же синтаксис, что и 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

Ответ 6

Следующий код работает в 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..."

Ответ 7

var testAwait = function () {
    var promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Inside test await');
        }, 1000);
    });
    return promise;
}

var asyncFunction = async function() {
    await testAwait().then((data) => {
        console.log(data);
    })
    return 'hello asyncFunction';
}

asyncFunction().then((data) => {
    console.log(data);
});

//Inside test await
//hello asyncFunction

Ответ 8

Это быстрее исправить в одной строке.

Надеюсь, это поможет.

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