How would I make these await functions run sequentially? [duplicate] - javascript

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
}
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.

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 recommend:
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.

The quick one-liner, inline way
await new Promise(resolve => setTimeout(resolve, 1000));

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")
})()

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.
Update: Modern node.js versions has a buid-in async timeout implementation, accessible via util.promisify helper:
const {promisify} = require('util');
const setTimeoutAsync = promisify(setTimeout);

Timers Promises API
await setTimeout finally arrived with Node.js 16, removing the need to use util.promisify():
import { setTimeout } from 'timers/promises';
(async () => {
const result = await setTimeout(2000, 'resolved')
// Executed after 2 seconds
console.log(result); // "resolved"
})()
Official Node.js docs: Timers Promises API (library already built in Node)

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

I leave this code snippet here for someone who wants to fetch API call (e.g. get clients) with setTimeout:
const { data } = await new Promise(resolve => setTimeout(resolve, 250)).then(() => getClientsService())
setName(data.name || '')
setEmail(data.email || '')

await new Promise(resolve => setTimeout(() => { resolve({ data: 'your return data'}) }, 1000))

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

This is my version with nodejs now in 2020 in AWS labdas
const sleep = require('util').promisify(setTimeout)
async function f1 (some){
...
}
async function f2 (thing){
...
}
module.exports.someFunction = async event => {
...
await f1(some)
await sleep(5000)
await f2(thing)
...
}

await setTimeout(()=>{}, 200);
Will work if your Node version is 15 and above.

Made a util inspired from Dave's answer
Basically passed in a done callback to call when the operation is finished.
// Function to timeout if a request is taking too long
const setAsyncTimeout = (cb, timeout = 0) => new Promise((resolve, reject) => {
cb(resolve);
setTimeout(() => reject('Request is taking too long to response'), timeout);
});
This is how I use it:
try {
await setAsyncTimeout(async done => {
const requestOne = await someService.post(configs);
const requestTwo = await someService.get(configs);
const requestThree = await someService.post(configs);
done();
}, 5000); // 5 seconds max for this set of operations
}
catch (err) {
console.error('[Timeout] Unable to complete the operation.', err);
}

The following code works in Chrome and Firefox and maybe other browsers.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
await timeout(3000);
return fn(...args);
}
But in Internet Explorer I get a Syntax Error for the "(resolve **=>** setTimeout..."

How to Log all the responses at once?
async function sayHello(name) {
let greet = `Hey! ${name} very nice to meet you bud.`;
setTimeout(() => {
return {
greet,
createdAt: new Date(),
};
}, 1000);
}
const response1 = async () => await sayHello("sounish");
const response2 = async () => await sayHello("alex");
const response3 = async () => await sayHello("bill");
async function getData() {
const data1 = await sayHello("sounish");
const data2 = await sayHello("alex");
const data3 = await sayHello("bill");
return { data1, data2, data3 };
}
Promise.all([sayHello("sounish"), sayHello("alex"), sayHello("bill")]).then(
(allResponses) => {
console.log({ allResponses });
}
);
getData().then((allData) => {
console.log({ allData });
});

I would like to point out a robust extension to Promise.all. A rather elegant solution that works with one promise to be time-limited only is to race the promise with a timeout (such as new Promise((resolve) => setTimeout(resolve, timeout))).
await new Promise.race([myPromise, timeoutPromise])
will continue as soon as one of the promises finished. myPromise then can internally await a different timeout, or simply make use of Promise.all
const timeout = ms => new Promise((resolve) => setTimeout(resolve, ms));
await Promise.race([
Promise.all([myPromise, timeout(500)]),
timeout(5000)
]);
The result is an asynchronous call that does not run more often than twice a second, with a timeout of 5 seconds in case of some (network/server?) error.
Moreover, you can make this very versatile and customizable function as such:
function callWithTimeout(promise, msTimeout=5000, throws=false) {
const timeout = ms => new Promise((resolve, reject) =>
setTimeout(throws ? reject : resolve, ms));
await Promise.race([
//depends whether you want to wait there or just pass the promise itself
Promise.all([promise, timeout(500)]),
timeout(msTimeout)
]);
}
Which ultimately lets you customize the timeout time and the whether the promise should succeed or throw on timeout. Having such robust general implementation can save you a lot of pain in the future. You can also set a string instead of boolean as throws and bind this variable to the reject for custom error message: reject.bind(undefined, throws)
Note that you should not pass your promise with await:
const myPromise = async x => x;
//will never time out and not because myPromise will finish immediatelly
callWithTimeout(await myPromise(), 200, true);
//will possibly timeout after 200 ms with an exception
callWithTimeout(myPromise(), 200, true);

With the marked answer I had a lint error [no-promise-executor-return] so I found here the corrected version, using curly brackets in order to make explicit the intention of not returning anything:
const timeout = (ms) =>
new Promise(resolve => {
setTimeout(resolve, ms)
})

This is a quicker fix in one-liner.
Hope this will help.
// WAIT FOR 200 MILISECONDS TO GET DATA //
await setTimeout(()=>{}, 200);

Related

I want to print functions return values by using Async Awaits functionality in javascript promises [duplicate]

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
}
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.
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 recommend:
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.
The quick one-liner, inline way
await new Promise(resolve => setTimeout(resolve, 1000));
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")
})()
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.
Update: Modern node.js versions has a buid-in async timeout implementation, accessible via util.promisify helper:
const {promisify} = require('util');
const setTimeoutAsync = promisify(setTimeout);
Timers Promises API
await setTimeout finally arrived with Node.js 16, removing the need to use util.promisify():
import { setTimeout } from 'timers/promises';
(async () => {
const result = await setTimeout(2000, 'resolved')
// Executed after 2 seconds
console.log(result); // "resolved"
})()
Official Node.js docs: Timers Promises API (library already built in Node)
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
I leave this code snippet here for someone who wants to fetch API call (e.g. get clients) with setTimeout:
const { data } = await new Promise(resolve => setTimeout(resolve, 250)).then(() => getClientsService())
setName(data.name || '')
setEmail(data.email || '')
await new Promise(resolve => setTimeout(() => { resolve({ data: 'your return data'}) }, 1000))
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
This is my version with nodejs now in 2020 in AWS labdas
const sleep = require('util').promisify(setTimeout)
async function f1 (some){
...
}
async function f2 (thing){
...
}
module.exports.someFunction = async event => {
...
await f1(some)
await sleep(5000)
await f2(thing)
...
}
await setTimeout(()=>{}, 200);
Will work if your Node version is 15 and above.
Made a util inspired from Dave's answer
Basically passed in a done callback to call when the operation is finished.
// Function to timeout if a request is taking too long
const setAsyncTimeout = (cb, timeout = 0) => new Promise((resolve, reject) => {
cb(resolve);
setTimeout(() => reject('Request is taking too long to response'), timeout);
});
This is how I use it:
try {
await setAsyncTimeout(async done => {
const requestOne = await someService.post(configs);
const requestTwo = await someService.get(configs);
const requestThree = await someService.post(configs);
done();
}, 5000); // 5 seconds max for this set of operations
}
catch (err) {
console.error('[Timeout] Unable to complete the operation.', err);
}
The following code works in Chrome and Firefox and maybe other browsers.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
await timeout(3000);
return fn(...args);
}
But in Internet Explorer I get a Syntax Error for the "(resolve **=>** setTimeout..."
How to Log all the responses at once?
async function sayHello(name) {
let greet = `Hey! ${name} very nice to meet you bud.`;
setTimeout(() => {
return {
greet,
createdAt: new Date(),
};
}, 1000);
}
const response1 = async () => await sayHello("sounish");
const response2 = async () => await sayHello("alex");
const response3 = async () => await sayHello("bill");
async function getData() {
const data1 = await sayHello("sounish");
const data2 = await sayHello("alex");
const data3 = await sayHello("bill");
return { data1, data2, data3 };
}
Promise.all([sayHello("sounish"), sayHello("alex"), sayHello("bill")]).then(
(allResponses) => {
console.log({ allResponses });
}
);
getData().then((allData) => {
console.log({ allData });
});
I would like to point out a robust extension to Promise.all. A rather elegant solution that works with one promise to be time-limited only is to race the promise with a timeout (such as new Promise((resolve) => setTimeout(resolve, timeout))).
await new Promise.race([myPromise, timeoutPromise])
will continue as soon as one of the promises finished. myPromise then can internally await a different timeout, or simply make use of Promise.all
const timeout = ms => new Promise((resolve) => setTimeout(resolve, ms));
await Promise.race([
Promise.all([myPromise, timeout(500)]),
timeout(5000)
]);
The result is an asynchronous call that does not run more often than twice a second, with a timeout of 5 seconds in case of some (network/server?) error.
Moreover, you can make this very versatile and customizable function as such:
function callWithTimeout(promise, msTimeout=5000, throws=false) {
const timeout = ms => new Promise((resolve, reject) =>
setTimeout(throws ? reject : resolve, ms));
await Promise.race([
//depends whether you want to wait there or just pass the promise itself
Promise.all([promise, timeout(500)]),
timeout(msTimeout)
]);
}
Which ultimately lets you customize the timeout time and the whether the promise should succeed or throw on timeout. Having such robust general implementation can save you a lot of pain in the future. You can also set a string instead of boolean as throws and bind this variable to the reject for custom error message: reject.bind(undefined, throws)
Note that you should not pass your promise with await:
const myPromise = async x => x;
//will never time out and not because myPromise will finish immediatelly
callWithTimeout(await myPromise(), 200, true);
//will possibly timeout after 200 ms with an exception
callWithTimeout(myPromise(), 200, true);
With the marked answer I had a lint error [no-promise-executor-return] so I found here the corrected version, using curly brackets in order to make explicit the intention of not returning anything:
const timeout = (ms) =>
new Promise(resolve => {
setTimeout(resolve, ms)
})
This is a quicker fix in one-liner.
Hope this will help.
// WAIT FOR 200 MILISECONDS TO GET DATA //
await setTimeout(()=>{}, 200);

Is async code in a Promise always an antipattern?

I see from this question that it can be an antipattern to mix Promises with async code.
Does this, however, apply in all cases?
I can't see an easy way to avoid combining them in the following code:
It's an alternative to setInterval which waits for an invocation to complete before scheduling the next one
However, unlike recursive setTimeout, it does not constitute an open memory leak in browsers that don't yet support TCO
Does this code embody an antipattern? And, if so, how can I remedy it without introducing a memory leak?
See, in particular, line 10: new Promise( async (resolve) => {
—this seems very non-idiomatic, but I don't see another way to accomplish: wrapping an await statement in a while loop per se, dispatching it, and returning a handle to abort the loop.
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments);
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
<p><button onclick="(function createInterval(){
const _ = {intervalID: undefined};
_.intervalID = setRepeatedTimeout( () => {
console.log(`Hello from intervalID ${_.intervalID}`)
}, 2000)
})()">Create timer</button><br />
<form action="javascript:void(0);" onsubmit="(function clearInterval(intervalID){
clearRepeatedTimeout(intervalID);
})(parseInt(event.target.elements.intervalID.value))">
<input name="intervalID" placeholder="intervalID"/><button type="submit">Clear timer</button></p>
The problem that the other question was warning about, and that could be a problem here, is that if the inside of the async callback passed to the Promise constructor awaits something that rejects, the Promise will hang instead of rejecting. Your current code will not result in f ever rejecting, but setRepeatedTimeout were to carry out a task which may reject, you'd get an unhandled rejection and permanent hanging:
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments);
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
If you want the loop to continue when such an error is encountered, there's a way to handle such problems while keeping the async: just catch everything that might reject (either in a try/catch or with .catch):
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
But there's really no need for the new Promise here at all - it never resolves, and never gets used. Just use an async IIFE:
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
(async () => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
})();
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
(async () => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
})();

How to mock a delay in my api call function?

I have a function to update an user with an api post request. The backend is not done yet. The function will thus always return an error. In order to test the loading and error states, I would like to temporarily add a fake delay before returning the result. How to do so? Here is the function:
const updateProfile = async (form) => {
try {
const res = await api.post("/update-profile", form);
return res;
} catch (err) {
throw new Error("error.unknown");
}
};
Writing this didn't work:
const updateProfile = async (form) => {
try {
let fakeCallDone = false
setTimeout(()=> fakeCallDone = true, 2000)
const res = await api.post("/update-profile", form);
fakeCallDone && res;
} catch (err) {
throw new Error("error.unknown");
}
};
You can create a simple sleep function.
const sleep = ms => new Promise(
resolve => setTimeout(resolve, ms));
And then use like
await sleep(2000);
The problem is here:
setTimeout(()=> fakeCallDone = true, 2000)
It will move on to Web API then continue to execute the next line codes.
[Solution]
const updateProfile = async (form) => {
try {
var res = api.post("/update-profile", form); // this async code will move on `web api`. When it's done will move on to queue.
await delay(2000); // You mock a delay here
return await res; // Resolve value from `res` promise.
} catch (err) {
throw new Error("error.unknown");
}
};
delay() method look like this:
const delay= ms => new Promise(resolve => setTimeout(resolve, ms));
Note: you should get more details about event loop to know
How js works: call stack, web API, queue, event loop
Async programming in Javascript.
You can return a new promise in the meantime (Until the backend is ready):
const updateProfile = async () => {
try {
// const res = await api.post("/update-profile", form);
// return res;
return new Promise((res, rej) => {
setTimeout(() => res('response'), 2000)
})
} catch (err) {
throw new Error("error.unknown");
}
};
updateProfile().then(console.log)

How to cover setInterval in the unit test case in javascript

Hi I am write a unit test case of this function. When I run this function from the unit test case then it covers all statements but setInterval complete lines are not covered.
Does anyone know how to cover it in javascript? I am using mocha.
const open = async function (config) {
...... set of lines..
let retryIn = setInterval(async () => {
try {
client = await connect(config);
clearInterval(retryIn);
return client;
} catch (err) {
//error
}
}, 20000);
};
I am simply calling it like this
it("###test", async () => {
open(config);
});
});
First of all, you should never use setInterval in the case where you want to retry a task that has failed. You should use setTimeout instead.
Besides that, you cannot return a value from a classical callback base function like setInterval or setTimeout. So in its current form, the promise returned when calling open will be resolved before any connection is made.
With await/async you can create a clean and simple setup for such a situation:
function wait(seconds) {
return new Promise((resolve, _) => setTimeout(resolve, seconds))
}
async function connect() {
throw new Error('failed')
}
async function open(config) {
let client;
while (client === undefined /* || retries > maxRetries*/ ) {
try {
client = await connect(config);
} catch (err) {
// if connection failed due to an error, wait n seconds and retry
console.log('failed wait 2 seconds for reconnect');
await wait(2000)
// ++retries
}
}
if (!client) {
throw new Error('connection failed due to max number of retries reached.')
}
return client
}
async function main() {
let connection = await open()
}
main().catch(err => console.log(err))
You can further extend this snippet by adding a retry limit. See the comments for a rough idea on how that can be achieved.
To test the above code, you would write:
it("###test", function() {
return open(config);
});
Someone posted an answer about fake timers and then deleted it , The answer was correct so I re-posted again.
You can use sinonjs to create fake timers
Fake timers are synchronous implementations of setTimeout and friends
that Sinon.JS can overwrite the global functions with to allow you to
more easily test code using them
But from your code, it seems you are trying to test async code, in mocha, this can be achieved like this
describe('somthing', () => {
it('the result is 2', async () => {
const x = await add(1, 1)
expect(x).to.equal(4);
});
});
With something closer to your code
async function open() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('done')
}, 1000);
});
};
describe('somthing', () => {
it('###test', async () => {
const x = await open()
chai.expect(x).to.equal("done");
});
});
Just wrap to Promise
const open = async function (config) {
...... set of lines..
return new Promise((resolve, reject) => {
let retryIn = setInterval(async () => {
client = await connect(asConfigParam);
clearInterval(retryIn);
return client;
}, 20000);
return resolve(retryIn);
});
};
it("###test", async () => {
const result = await open(config);
console.log('result', result)
});

Why the function is called before the first one when it does have await [duplicate]

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
}
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.
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 recommend:
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.
The quick one-liner, inline way
await new Promise(resolve => setTimeout(resolve, 1000));
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")
})()
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.
Update: Modern node.js versions has a buid-in async timeout implementation, accessible via util.promisify helper:
const {promisify} = require('util');
const setTimeoutAsync = promisify(setTimeout);
Timers Promises API
await setTimeout finally arrived with Node.js 16, removing the need to use util.promisify():
import { setTimeout } from 'timers/promises';
(async () => {
const result = await setTimeout(2000, 'resolved')
// Executed after 2 seconds
console.log(result); // "resolved"
})()
Official Node.js docs: Timers Promises API (library already built in Node)
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
I leave this code snippet here for someone who wants to fetch API call (e.g. get clients) with setTimeout:
const { data } = await new Promise(resolve => setTimeout(resolve, 250)).then(() => getClientsService())
setName(data.name || '')
setEmail(data.email || '')
await new Promise(resolve => setTimeout(() => { resolve({ data: 'your return data'}) }, 1000))
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
This is my version with nodejs now in 2020 in AWS labdas
const sleep = require('util').promisify(setTimeout)
async function f1 (some){
...
}
async function f2 (thing){
...
}
module.exports.someFunction = async event => {
...
await f1(some)
await sleep(5000)
await f2(thing)
...
}
await setTimeout(()=>{}, 200);
Will work if your Node version is 15 and above.
Made a util inspired from Dave's answer
Basically passed in a done callback to call when the operation is finished.
// Function to timeout if a request is taking too long
const setAsyncTimeout = (cb, timeout = 0) => new Promise((resolve, reject) => {
cb(resolve);
setTimeout(() => reject('Request is taking too long to response'), timeout);
});
This is how I use it:
try {
await setAsyncTimeout(async done => {
const requestOne = await someService.post(configs);
const requestTwo = await someService.get(configs);
const requestThree = await someService.post(configs);
done();
}, 5000); // 5 seconds max for this set of operations
}
catch (err) {
console.error('[Timeout] Unable to complete the operation.', err);
}
The following code works in Chrome and Firefox and maybe other browsers.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
await timeout(3000);
return fn(...args);
}
But in Internet Explorer I get a Syntax Error for the "(resolve **=>** setTimeout..."
How to Log all the responses at once?
async function sayHello(name) {
let greet = `Hey! ${name} very nice to meet you bud.`;
setTimeout(() => {
return {
greet,
createdAt: new Date(),
};
}, 1000);
}
const response1 = async () => await sayHello("sounish");
const response2 = async () => await sayHello("alex");
const response3 = async () => await sayHello("bill");
async function getData() {
const data1 = await sayHello("sounish");
const data2 = await sayHello("alex");
const data3 = await sayHello("bill");
return { data1, data2, data3 };
}
Promise.all([sayHello("sounish"), sayHello("alex"), sayHello("bill")]).then(
(allResponses) => {
console.log({ allResponses });
}
);
getData().then((allData) => {
console.log({ allData });
});
I would like to point out a robust extension to Promise.all. A rather elegant solution that works with one promise to be time-limited only is to race the promise with a timeout (such as new Promise((resolve) => setTimeout(resolve, timeout))).
await new Promise.race([myPromise, timeoutPromise])
will continue as soon as one of the promises finished. myPromise then can internally await a different timeout, or simply make use of Promise.all
const timeout = ms => new Promise((resolve) => setTimeout(resolve, ms));
await Promise.race([
Promise.all([myPromise, timeout(500)]),
timeout(5000)
]);
The result is an asynchronous call that does not run more often than twice a second, with a timeout of 5 seconds in case of some (network/server?) error.
Moreover, you can make this very versatile and customizable function as such:
function callWithTimeout(promise, msTimeout=5000, throws=false) {
const timeout = ms => new Promise((resolve, reject) =>
setTimeout(throws ? reject : resolve, ms));
await Promise.race([
//depends whether you want to wait there or just pass the promise itself
Promise.all([promise, timeout(500)]),
timeout(msTimeout)
]);
}
Which ultimately lets you customize the timeout time and the whether the promise should succeed or throw on timeout. Having such robust general implementation can save you a lot of pain in the future. You can also set a string instead of boolean as throws and bind this variable to the reject for custom error message: reject.bind(undefined, throws)
Note that you should not pass your promise with await:
const myPromise = async x => x;
//will never time out and not because myPromise will finish immediatelly
callWithTimeout(await myPromise(), 200, true);
//will possibly timeout after 200 ms with an exception
callWithTimeout(myPromise(), 200, true);
With the marked answer I had a lint error [no-promise-executor-return] so I found here the corrected version, using curly brackets in order to make explicit the intention of not returning anything:
const timeout = (ms) =>
new Promise(resolve => {
setTimeout(resolve, ms)
})
This is a quicker fix in one-liner.
Hope this will help.
// WAIT FOR 200 MILISECONDS TO GET DATA //
await setTimeout(()=>{}, 200);

Categories