I have created three Promises as follows and awaited them, expecting them to take 6000 milliseconds:
let PromiseOne = new Promise(resolve => {
setTimeout(() => {
resolve('Promise One');
}, 2000);
});
let PromiseTwo = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Two');
}, 2000);
});
let PromiseThree = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Three');
}, 2000);
});
(async() => {
console.time();
let ResponseOne = await PromiseOne;
let ResponseTwo = await PromiseTwo;
let ResponseThree = await PromiseThree;
console.log(ResponseOne, ResponseTwo, ResponseThree);
console.timeEnd();
})();
But, I have received an unexpected console message as follows.
Promise One Promise Two Promise Three
default: 2.004s
As I know, each await has 2000ms of running time. But, It doesn't.
In this case, what is the difference between my code above using async/await and the code below using Promise.all?
let PromiseOne = new Promise(resolve => {
setTimeout(() => {
resolve('Promise One');
}, 2000);
});
let PromiseTwo = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Two');
}, 2000);
});
let PromiseThree = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Three');
}, 2000);
});
(() => {
Promise.all([PromiseOne, PromiseTwo, PromiseThree]).then(res => {
console.log(res);
});
})();
In both cases, you're constructing all the Promises immediately. After the declaration of PromiseThree ends, for both, you're left with 3 promises, each of which resolves after 2 seconds. No matter what happens later in the script, each of those will resolve after 2 seconds.
If you use Promise.all, all of the promises will have resolved after 2 seconds.
If you use async/await, the first one you wait for will take 2 seconds to resolve. At that same time, the other two will have resolved, so doing await PromiseTwo and await PromiseThree will take next to no time at all - so, still a total of 2 seconds.
// at this point, each promise has been created and each will take 2 seconds
(async() => {
console.time();
// 2 seconds for the below line
let ResponseOne = await PromiseOne;
// after 2 seconds, all have resolved; below line takes no time at all
let ResponseTwo = await PromiseTwo;
// same as above
let ResponseThree = await PromiseOne;
It'd be different if you constructed the other promises after awaiting the previous ones - in which case they'd run in serial as you're expecting with await.
let makePromise = () => new Promise(resolve => {
setTimeout(() => {
resolve();
}, 2000);
});
console.log('starting');
(async () => {
console.time();
await makePromise();
await makePromise();
await makePromise();
console.timeEnd();
})();
Related
I am new to Javascript and trying to learn promises and async/await concepts. I created three promises as shown below.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});
I have created a async function which is using await for multiple promises sequentially as shown below.
async function example() {
const result1 = await promise1;
const result2 = await promise2;
const result3 = await promise3;
console.log(result1);
console.log(result2);
console.log(result3);
}
example();
The output in browser console is -
promise1
promise3
promise2
1
2
3
I am not understanding why in my output promise3 is coming before promise2 because in sequence of await statements inside async function example, promise2 comes before promise3? According to me the output should be like below -
promise1
promise2
promise3
1
2
3
Please correct me if I am missing something or if there is any error.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
When you construct a promise, the code inside it runs immediately. So as soon as this line is done, a timer is off and running. Your code creates the 3 of these promises up front, which means it starts all 3 timers up front.
Later on when you await the promise, that does not change what the timers are doing. It just lets your async function know when they are done. So in the background, the timers will start going off, logging things out, and resolving their corresponding promises. This can happen even if nothing is awaiting the promise. The timeout of 1000ms will be the first to go off, followed 3 seconds later by the one of 4000ms, and then 1 second later the one of 5000ms
If you want the timers to only start once you get to that line of the async function, then you need to do the setTimeouts at that line of the async function. For example:
async function example() {
const result1 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000);
});
const result2 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000);
});
const result3 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000);
});
console.log(result1);
console.log(result2);
console.log(result3);
}
In a nutshell, it's because you first create those three promises and in the process of creating those three promises, you also start your three timers. Those three timers are all started and are all running in parallel.
Then, you do await promise1. But, that statement has nothing at all to do with when the timers call their callback. They will do that entirely upon their own. Thus, the timer callbacks themselves create console.log() output according to the expected time each timer is set for (nothing at all to do with the await you have).
So, it happens this way because your first create all three promises and timers and THEN and only then, do you do an await. An important thing to understand here is that "promises don't execute". They aren't the asynchronous operation themselves. As soon as you do new Promise(), it calls the promise executor function and the asynchronous operation you have in there is started. What the promise does from then on is monitor that asynchronous operation and then notify observers when that asynchronous operation completes.
You can see more detail on the order of things if you add logging for when each timer is started which will show that all three timers are initially started and running in parallel and can call their timer callbacks completely independent of your await statements later in the code:
const promise1 = new Promise((resolve, reject) => {
console.log("starting timer 1");
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
const promise2 = new Promise((resolve, reject) => {
console.log("starting timer 2");
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
const promise3 = new Promise((resolve, reject) => {
console.log("starting timer 3");
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});
async function example() {
const result1 = await promise1;
const result2 = await promise2;
const result3 = await promise3;
console.log(result1);
console.log(result2);
console.log(result3);
}
example();
If you changed the structure of your code so that a function you were awaiting is what actually creates and starts the timers, then you wouldn't be starting the second timer until after the first timer fires and you'd have sequential timers.
So, your expected output would happen if you did this instead:
function runTimer1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
}
function runTimer2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
}
function runTimer3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});
}
async function example() {
const result1 = await runTimer1();
const result2 = await runTimer2();
const result3 = await runTimer3();
console.log(result1);
console.log(result2);
console.log(result3);
}
example();
That's because you're creating the Promises outside of the async function without awaiting. The callback inside the Promise is syncrounos. You run the 3 setTimeout's one after another. Example:
const x = new Promise(resolve => console.log(1))
console.log(2)
This logs out 1,2 - as opposed to asyncrounous callbacks ex. in setTimeout's:
setTimeout(() => console.log(1));
console.log(2)
This logs out 2,1.
So, if you want the correct behaviour you'd have to create the Promises when you await for them, and that's common practice:
function makePromise(time, number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise", number);
resolve(number);
}, time);
});
}
async function example() {
const result1 = await makePromise(1000, 1);
const result2 = await makePromise(5000, 2);
const result3 = await makePromise(4000, 3);
console.log(result1);
console.log(result2);
console.log(result3);
}
example();
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 callback timer() function after forEach loop is finished, using the same code. or is there is a better way to loop through each user with delay then after the loop is done, the timer() is called back using forEach.
const usersProfile = () => {
let interval = 1000;
let promise = Promise.resolve();
db.select('*').from('users')
.returning('*')
.then(users => {
users.forEach((user, index) => {
setTimeout(function(){
}, index * 1000)
db.select('*').from(`${user.name}`)
.returning('*')
.then(userdata => {
userdata.forEach(data => {
promise = promise.then(function(){
if(data.status === 'online'){
console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`)
}
return new Promise(function(resolve){
setTimeout(function(){
resolve();
}, interval)
})
})
})
})
})
timer();
})
}
const timer = () => {
setTimeout(usersProfile, 1000)
}
timer();
===============ALL THE ABOVE ARE MY OLD CODE ================
but thanks to https://stackoverflow.com/users/2404452/tho-vu it solved most of the problem but can i do this to serve the purpose of the app
const usersProfile = async () => {
let interval = 1000;
const delayPromise = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
if(data.status === 'online'){
console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`);
resolve();
}
}, delayDuration)
});
};
const userInfo = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`${data.info}`);//info about user from his table each user has his own table besides users table that has only the user tables
resolve();
}, delayDuration)
});
};
try {
const userData = await db.select('*').from('users').returning('*');
const promises = userData.map((data, index) => delayPromise(data, index * interval));
const userData = await db.select('*').from(`${data.name}`).returning('*');
const info = userData.map((data, index) => userInfo(data, index * interval));
await Promise.all(promises);
// here you can write your effects
} catch (e) {
console.log(e);
}
}
Another approach using async-await to avoid callback hell.
const usersProfile = async () => {
let interval = 1000;
const delayPromise = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
if(data.status === 'online'){
console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`);
resolve();
}
}, delayDuration)
});
};
try {
const userData = await db.select('*').from('users').returning('*');
const promises = userData.map((data, index) => delayPromise(data, index * interval));
await Promise.all(promises);
// here you can write your effects
} catch (e) {
console.log(e);
}
}
it is hard for me to fully understand what you wanted to accomplish through the code, but I will try to explain what you can do to solve the issue.
First of all, if you want to wait for multiple promises, you should use Promise.all and not promise = promise.then
You can do this as so:
let promises = [];
users.forEach((user, index) => {
let promise = db.select(*).from('users') //should return a promise
promises.push(promise);
});
//promises have already started to execute (in parallel)
Promise.all(promises)
.then(() => console.log('all promises finished successfully'))
.catch((e) => console.error('received error at one of the promises'));
// when the program arrives here we know for a fact that either all promises executed successfully or one of the promises failed
timer();
Explanation: because promises execute asynchronously the forEach() function does not wait for any of the promises created to finish, so the solution is to wait for all of them at then after the entire loop.
This means the promises are created, and are being executed while the forEach() loop executes, in parallel, and when the program reaches Promise.all it stops and waits for all of them to finish.
Second, I would strongly advice you to use functions as a way to simplify your code, that way it would be easier for you to grasp every thing that is happening, even if its complicated.
Good luck !
I have the code on Promise:
function one() {
return new Promise((rs,er)=>{
console.log('start');
new Promise((rr,err)=>{setTimeout(()=>{console.log('after 3 sec');rr()},3000)})
.then( sd => {
console.log('endLong');
rs();
})
});
}
one().then(_ => one()).then(_ => one());
And as a result I get syncronized code.
But when I refactoring it to async/wait
async function one() {
console.log('start');
await longtime();
console.log('endLong');
}
async function longtime() {setTimeout(()=>{console.log('after 3 sec');},3000);}
one().then(_ => one()).then(_ => one())
then I got:
start
endLong
start
endLong
start
endLong
Promise {<resolved>: undefined}
after 3 sec
after 3 sec
after 3 sec
What's wrong?
You need longtime to return a promise. A setTimeout alone does not mean anything to promise-based async/await:
async function one() {
console.log('start');
await longtime();
console.log('endLong');
}
const longtime = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('after 0.5 sec');
resolve();
}, 500);
});
one()
.then(_ => one())
.then(_ => one())
setTimeout does not return a promise. An async function should return a promise that's resolved with the value.
function longtime() {
return new Promise(resolve => {
setTimeout(() => {
console.log('after 3 sec');
resolve();
}, 3000);
});
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);