Combination of async function + await + setTimeout

Combination of async function + await + setTimeout

I am trying to use the new async features and I hope solving my problem will help others in the future. This is my code which is working:
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
});
}

The problem is, that my while loop runs too fast and the script sends too many requests per second to the google API. Therefore I would like to build a sleep function which delays the request. Thus I could also use this function to delay other requests. If there is another way to delay the request, please let me know.
Anyway, this is my new code which does not work. The response of the request is returned to the anonymous async function within the setTimeout, but I just do not know how I can return the response to the sleep function resp. to the initial asyncGenerator function.
async function asyncGenerator() {
// other code
while (goOn) {
// other code
var fileList = await sleep(listFiles, nextPageToken);
var parents = await requestParents(fileList);
// other code
}
// other code
}

Related:  Convert ES6 Iterable to Array

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

I have already tried some options: storing the response in a global variable and return it from the sleep function, callback within the anonymous function, etc.

Solutions/Answers:

Solution 1:

Your sleep function does not work because setTimeout does not (yet?) return a promise that could be awaited. You will need to promisify it manually:

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

Btw, to slow down your loop you probably don’t want to use a sleep function that takes a callback and defers it like this. I’d rather recommend to do something like

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

which lets the computation of parents take at least 5 seconds.

Solution 2:

Since Node 7.6, you can combine the functions promisify function from the utils module with setTimeout() .

Node.js

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

Javascript

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

Usage

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

Solution 3:

The quick one-liner, inline way

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

Solution 4:

setTimeout is not an async function, so you can’t use it with ES7 async-await. But you could implement your sleep function using ES6 Promise:

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

Then you’ll be able to use this new sleep function with ES7 async-await:

var fileList = await sleep(listFiles, nextPageToken)

Please, note that I’m only answering your question about combining ES7 async/await with setTimeout, though it may not help solve your problem with sending too many requests per second.

Related:  Catch all unhandled javascript promise rejections

Solution 5:

If you would like to use the same kind of syntax as setTimeout you can write a helper function like this:

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

You can then call it like so:

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

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

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

doStuffAsync();

I made a gist: https://gist.github.com/DaveBitter/f44889a2a52ad16b6a5129c39444bb57