This question already has answers here:
Why does nodejs stop execution of while true loop inside async function
(3 answers)
Closed 28 days ago.
I have a sample code on TS playground represents my problem.
In an async function, I log the result after await for the promise, but only the code inside promise run, not the log outside of it. Could someone explain this problem?
Here is the code:
const asyncFnc = async () => {
let result = false;
await new Promise(resolve => {
setTimeout(() => {
// This log worked
console.log('waited 5s');
result = true;
}, 5000);
});
// This log did not worked
console.log(result);
}
asyncFnc();
And the result:
await sends the parent function to sleep until the promise on the right hand side settles (i.e. resolves or rejects).
Your promise never resolves or rejects. (i.e. you don't call resolve, make use of the second argument, or throw an exception).
Thus the parent function sleeps forever.
The idiomatic way to write this would be to avoid setting variables in the wider scope as a side effect, and just resolve with the values instead.
const asyncFnc = async () => {
const result = await new Promise(resolve => {
setTimeout(() => {
console.log('waited 5s');
resolve(true);
}, 5000);
});
console.log(result);
}
asyncFnc();
You need to call resolve() in your timeout
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let interval = async ()=>{
await setInterval(first,2000)
await setInterval(second,2000)
}
interval();
Imagine that I have this code above.
When I run it, first() and second() will be called at the same time; how do I call second() after first)() returns some data, for example, if first() is done, only then call second()?
Because first() in my code will be working with a big amount of data and if this 2 functions will be calling at the same time, it will be hard for the server.
How do I call second() each time when first() will return some data?
As mentioned above setInterval does not play well with promises if you do not stop it. In case you clear the interval you can use it like:
async function waitUntil(condition) {
return await new Promise(resolve => {
const interval = setInterval(() => {
if (condition) {
resolve('foo');
clearInterval(interval);
};
}, 1000);
});
}
Later you can use it like
const bar = waitUntil(someConditionHere)
You have a few problems:
Promises may only ever resolve once, setInterval() is meant to call the callback multiple times, Promises do not support this case well.
Neither setInterval(), nor the more appropriate setTimeout() return Promises, therefore, awaiting on them is pointless in this context.
You're looking for a function that returns a Promise which resolves after some times (using setTimeout(), probably, not setInterval()).
Luckily, creating such a function is rather trivial:
async function delay(ms) {
// return await for better async stack trace support in case of errors.
return await new Promise(resolve => setTimeout(resolve, ms));
}
With this new delay function, you can implement your desired flow:
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let run = async ()=>{
await delay(2000);
first();
await delay(2000)
second();
}
run();
setInterval doesn't play well with promises because it triggers a callback multiple times, while promise resolves once.
It seems that it's setTimeout that fits the case. It should be promisified in order to be used with async..await:
async () => {
await new Promise(resolve => setTimeout(() => resolve(first()), 2000));
await new Promise(resolve => setTimeout(() => resolve(second()), 2000));
}
await expression causes async to pause until a Promise is settled
so you can directly get the promise's result without await
for me, I want to initiate Http request every 1s
let intervalid
async function testFunction() {
intervalid = setInterval(() => {
// I use axios like: axios.get('/user?ID=12345').then
new Promise(function(resolve, reject){
resolve('something')
}).then(res => {
if (condition) {
// do something
} else {
clearInterval(intervalid)
}
})
}, 1000)
}
// you can use this function like
testFunction()
// or stop the setInterval in any place by
clearInterval(intervalid)
You could use an IFFE. This way you could escape the issue of myInterval not accepting Promise as a return type.
There are cases where you need setInterval, because you want to call some function unknown amount of times with some interval in between.
When I faced this problem this turned out to be the most straight-forward solution for me. I hope it help someone :)
For me the use case was that I wanted to send logs to CloudWatch but try not to face the Throttle exception for sending more than 5 logs per second. So I needed to keep my logs and send them as a batch in an interval of 1 second. The solution I'm posting here is what I ended up using.
async function myAsyncFunc(): Promise<string> {
return new Promise<string>((resolve) => {
resolve("hello world");
});
}
function myInterval(): void {
setInterval(() => {
void (async () => {
await myAsyncFunc();
})();
}, 5_000);
}
// then call like so
myInterval();
Looked through all the answers but still didn't find the correct one that would work exactly how the OP is asked. This is what I used for the same purpose:
async function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (await callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})()
In my example, I also put interval iteration count and the timer itself, just in case the caller would need to do something with it. However, it's not necessary
In my case, I needed to iterate through a list of images, pausing in between each, and then a longer pause at the end before re-looping through.
I accomplished this by combining several techniques from above, calling my function recursively and awaiting a timeout.
If at any point another trigger changes my animationPaused:boolean, my recursive function will exit.
const loopThroughImages = async() => {
for (let i=0; i<numberOfImages; i++){
if (animationPaused) {
return;
}
this.updateImage(i);
await timeout(700);
}
await timeout(1000);
loopThroughImages();
}
loopThroughImages();
Async/await do not make the promises synchronous.
To my knowledge, it's just a different syntax for return Promise and .then().
Here i rewrote the async function and left both versions, so you can see what it really does and compare.
It's in fact a cascade of Promises.
// by the way no need for async there. the callback does not return a promise, so no need for await.
function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
// async function with async/await, this code ...
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})() //... returns a pending Promise and ...
console.log('i do not wait');
// ... is kinda identical to this code.
// still asynchronous but return Promise statements with then cascade.
(() => {
console.log('start again');
return waitInterval(first, 1000).then(() => {
return waitInterval(second, 1000).then(() => {
console.log('finish again');
});
});
})(); // returns a pending Promise...
console.log('i do not wait either');
You can see the two async functions both execute at the same time.
So using promises around intervals here is not very useful, as it's still just intervals, and promises changes nothing, and make things confusing...
As the code is calling callbacks repeatedly into an interval, this is, i think, a cleaner way:
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function executeThroughTime(...callbacks){
console.log('start');
let callbackIndex = 0; // to track current callback.
let timerIndex = 0; // index given to callbacks
let interval = setInterval(() =>{
if (callbacks[callbackIndex](timerIndex++)){ // callback return true when it finishes.
timerIndex = 0; // resets for next callback
if (++callbackIndex>=callbacks.length){ // if no next callback finish.
clearInterval(interval);
console.log('finish');
}
}
},1000)
}
executeThroughTime(first,second);
console.log('and i still do not wait ;)');
Also, this solution execute a callback every secondes.
if the callbacks are async requests that takes more than one sec to resolve, and i can't afford for them to overlap, then, instead of doing iterative call with repetitive interval, i would get the request resolution to call the next request (through a timer if i don't want to harass the server).
Here the "recursive" task is called lTask, does pretty much the same as before, except that, as i do not have an interval anymore, i need a new timer each iteration.
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync1(i) {
console.log(`first pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that first big data'), Math.floor(Math.random()*1000)+ 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{
console.log(`first solved: ${i} ->`, result);
return i==2;
});
}
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync2(i) {
console.log(`second pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that second big data'), Math.floor(Math.random()*1000) + 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{ // promise is resolved
console.log(`second solved: ${i} ->`,result);
return i==4; // return a promise
});
}
function executeThroughTime(...asyncCallbacks){
console.log('start');
let callbackIndex = 0;
let timerIndex = 0;
let lPreviousTime = Date.now();
let lTask = () => { // timeout callback.
asyncCallbacks[callbackIndex](timerIndex++).then((result) => { // the setTimeout for the next task is set when the promise is solved.
console.log('result',result)
if (result) { // current callback is done.
timerIndex = 0;
if (++callbackIndex>=asyncCallbacks.length){//are all callbacks done ?
console.log('finish');
return;// its over
}
}
console.log('time elapsed since previous call',Date.now() - lPreviousTime);
lPreviousTime = Date.now();
//console.log('"wait" 1 sec (but not realy)');
setTimeout(lTask,1000);//redo task after 1 sec.
//console.log('i do not wait');
});
}
lTask();// no need to set a timer for first call.
}
executeThroughTime(simulateAsync1,simulateAsync2);
console.log('i do not wait');
Next step would be to empty a fifo with the interval, and fill it with web request promises...
This question already has answers here:
Combination of async function + await + setTimeout
(17 answers)
Closed 2 years ago.
I am trying to understand the asnyc await functionality.
Therefore, i want to use an asnyc function, resolve it and do the following logs sequentially afterwards.
How do I achieve this? Or am I understanding something fundamentally wrong?
const test = async function() {
console.log('hi 1');
await setTimeout(() => {
console.log('timout1')
}, 1000);
console.log('hi 2');
console.log('hi 3');
}
test()
Result
hi 1
hi 2
hi 3
timout1
Expected Result
hi 1
timout1
hi 2
hi 3
You can use await for promises only and the setTimeout function doesn't return a Promise. However you can await a Promise that is resolved using setTimeout like so which will give you the desired result.
So, the function execution will halt untill either the Promise being awaited gets resolved or gets rejected and then continue.
const test = async function() {
console.log('hi 1');
// return a new promise resolved after setTimeout callback is fired
await (new Promise((resolve, reject) => {
setTimeout(() => {
console.log('timout1')
resolve()
}, 1000)
}))
console.log('hi 2');
console.log('hi 3');
}
test()
Hope this helps !
I hope this code help you to understand async await.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('hi 1');
const result = await resolveAfter2Seconds();
console.log(result);
console.log('hi 2');
console.log('hi 3');
}
asyncCall();
This question already has answers here:
Combination of async function + await + setTimeout
(17 answers)
Closed 3 years ago.
I need to run various steps in a function but steps have to be run in a specific order. I tried to implement an Async function as follow:
async function test() {
await setTimeout(function() { console.log('1'); }, 5000);
await setTimeout(function() { console.log('2'); }, 2000);
console.log('3');
}
test();
The expected results in the console should be 1, 2, 3 but I get 3, 2, 1.
It seems that the await parameter is ignored.
EDIT
The setTimeout function is used in the illustrative example above only to simulate a heavy task. In my project, I will not use it. Indeed, I need to connect to a database then reformat the results before moving to the next steps. Even by including the async-await, 2 is logged-in before 1. In other words, empty lists are passed to my graphic because the async-await is not taken into consideration. Here my current code:
async function refreshData() {
myLabel = [];
myValues = [];
myJSON = [];
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database(fullPath + '/annex/data.db');
await new Promise(resolve => {
db.each('SELECT firstName, age FROM Info;', function(err, row) {
console.log('1');
myLabel.push(row.firstName);
myValues.push(row.age);
myJSON.push(JSON.stringify(row));
});
resolve(myValues);
resolve(myLabel);
resolve(myJSON);
});
console.log('2');
db.close();
popChart(myLabel, myValues);
popTable();
}
You can write a wait function:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function test() {
console.log('1');
await wait(5000);
console.log('2');
await wait(2000);
console.log('3');
}
test();
I've used the following
function wait(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
and then you just await this function in your method.
using this:
async function test() {
await new Promise(resolve => {
setTimeout(function() { console.log('1'); resolve(); }, 5000)
});
await new Promise(resolve => {
setTimeout(function() { console.log('2'); resolve(); }, 2000)
});
console.log('3');
}
test();
For using await on a function & waiting till the function executes, it must be running on a promise, so you can create a new function delay which calls setTimeout within itself but runs on promise, so it will return once the console is logged after timeout & the calling function will hold the execution until it gets the promise resolved
Read this for better understanding with more examples
function delay (val,time){
return new Promise((resolve,reject)=>{
setTimeout(function() { console.log(val); resolve(true) }, time);
});
}
async function test() {
await delay('1',5000);
await delay('2',2000);
console.log('3');
}
test();
The following JS code:
function promise_GetSomething() {
return new Promise(resolve => {
setTimeout(function () {
resolve("Something gotten after 3 sec.");
}, 3000);
});
}
async function logAboutSomethingGotten() {
console.log("Before getting 3-sec-something.");
var somethingGotten = await promise_GetSomething();
console.log(somethingGotten);
console.log("After getting 3-sec-something.");
}
function doSomething() {
console.log("START");
logAboutSomethingGotten();
console.log("STOP");
}
doSomething();
...prints the following:
START
Before getting 3-sec-something.
STOP
Something gotten after 3 sec.
After getting 3-sec-something.
How can I adjust it to print the following?
START
Before getting 3-sec-something.
Something gotten after 3 sec.
After getting 3-sec-something.
STOP
Also, if the async logAboutSomethingGotten() returns a value, how can the value be gotten and used synchronously?
EDIT (UTC 2019-01-12 11:14 PM):
Thanks to the current answerers. The current answers all mostly suggest making doSomething() async and await logAboutSomethingGotten(). I had known this too, but because it could lead to maybe an endless async-await code, I didn't like that solution. Also, the option involving piping a .then(function() { console.log("STOP"); }) unto logAboutSomethingGotten() too would easily somehow solve that but not in all scenarios, like for the synchronous part of my question.
So, I'm particularly interested in if logAboutSomethingGotten() returns a value (e.g. after making an Ajax call, because synchronous Ajax is being deprecated). By what clever means can I use this returned value in a synchronous flow?
Do this->
async function doSomething() {
console.log("START");
await logAboutSomethingGotten();
console.log("STOP");
}
Check the snip-
function promise_GetSomething() {
return new Promise(resolve => {
setTimeout(function () {
resolve("Something gotten after 3 sec.");
}, 3000);
});
}
async function logAboutSomethingGotten() {
console.log("Before getting 3-sec-something.");
var somethingGotten = await promise_GetSomething();
console.log(somethingGotten);
console.log("After getting 3-sec-something.");
}
async function doSomething() {
console.log("START");
await logAboutSomethingGotten();
console.log("STOP");
}
doSomething();
Just mark doSomething as async and then await the logAboutSomethingGotten(); call.
If the async logAboutSomethingGotten() returns a value, how can the value be gotten and used synchronously?
An asynchronous result can never be used synchronously. Of course, after waiting for the promise you can always use the return value as normal.
Set your doSomething function to also be asynchronous, and await logAboutSomethingGotten.
function promise_GetSomething() {
return new Promise(resolve => {
setTimeout(function () {
resolve("Something gotten after 3 sec.");
}, 3000);
});
}
async function logAboutSomethingGotten() {
console.log("Before getting 3-sec-something.");
var somethingGotten = await promise_GetSomething();
console.log(somethingGotten);
console.log("After getting 3-sec-something.");
}
async function doSomething() {
console.log("START");
await logAboutSomethingGotten();
console.log("STOP");
}
doSomething();