I have problem understanding how async function work in JavaScript. Let's take the code below:
async () => {
console.log(1);
setTimeout(() => console.log(2)
, 2000)
console.log(3);
}
I would expect that invocation of synchronous function inside async should block thread before executing further code. So I'd expect to get 1 -> 2 -> 3 instead I'm getting 1 -> 3 -> 2. Can't find explanation why it's happening and how to block thread to receive output 1 -> 2 -> 3.
I'm using Node 12 with serverless framework.
async itself won't wait until execution of setTimeout finished as you expect. As you can read from the documentation - find here for async:
An async function can contain an await expression that pauses the execution of the async function to wait for the passed Promise's resolution, then resumes the async function's execution and evaluates as the resolved value.
Just built a quick example to see the difference between async and await solution and just using setTimeout as it is in your example.
Consider the following example:
const getPromise = async () => {
return new Promise((resolve) => {
setTimeout(resolve, 3000);
});
}
const run = async () => {
console.log('run started');
setTimeout(() => console.log('setTimeout finised'), 2000);
console.log('setTimeout started');
const promise = await getPromise();
console.log('Promise resolved');
console.log('run finished');
}
run();
Steps explained:
Logging that function run execution started
Attaching an event to setTimeout which will be finished in ~2 seconds
Log into console that setTimeout started
Creating promise with getPromise function and with await keyword wait till resolve
In ~2 seconds setTimeout logs that it has been finished
In ~3 seconds from Promise the resolve function called
run function finishes its execution after resolve and logging.
I hope that helps you understand this portion of the code.
I would expect that invocation of synchronous function inside async should block thread before executing further code.
It does
So I'd expect to get 1 -> 2 -> 3 instead I'm getting 1 -> 3 -> 2.
setTimeout is not synchronous. It very explicitly is for queuing up a function to run later, after some time has passed.
Can't find explanation why it's happening and how to block thread to receive output 1 -> 2 -> 3.
You can't per se.
The closest you could come would be to replace setTimeout with a loop that runs around in circles until some time has passed… but that would be awful (it would lock up the UI for starters).
If you want to just run the three logs in order, then replace setTimeout with something that returns a promise and then await it (which would put the async function to sleep and let any other code continue to run until the promise resolved).
const timeout = function() {
return new Promise(function(res) {
setTimeout(() => {
console.log(2);
res();
}, 2000)
})
};
const x = async() => {
console.log(1);
await timeout();
console.log(3);
}
x();
Related
I have the following code:
const doWorkPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('#2 (async call)');
}, 0);
resolve('#3 (async call?)');
console.log('#1 (sync call)');
});
doWorkPromise.then((result) => {
console.log('Success!', result);
}).catch((error) => {
console.log('Error!', error);
});
The output is:
#1 (sync call)
Success! #3 (async call?)
#2 (async call)
I know that sync code lands on the call stack and the async code registers event-callback pair at the Node APIs, where the callback is moved to the callback queue after the event. The event loop is then going to take elements out of the callback queue only when the call stack is empty. Therefore, I expected to have the sync code executed first and then the async one in order, because the timeouts are 0s, like:
#1 (sync call)
#2 (async call)
Success! #3 (async call?)
Can someone please explain why resolve is executed before '#2 (async call)'?
reject is never executed.
resolved is executed before #2 because:
setTimeout puts a function on the time out queue
resolve resolves the promise
console.log logs #1
The function finished
doWorkPromise.then assigns a function to run when the promise resolves
The promise is already resolved so that function is executed
After the minimum timeout time passes the function passed to setTimeout is called and logs #2
Your code executes the following synchronously:
resolve('#3 (async call?)');
...so that promise gets immediately in a resolved state. The fact that you have started a timer, as no bearing on the promise... it is unrelated.
So the then callback on that promise will be triggered on the next processing of the job queue, and so you'll see "Success", right after the execution of the main, synchronous code has completed.
Somewhat later (yes, even setTimeout(..., 0) will introduce a small delay), the timer will expire, but that event has nothing to do with any promise.
The common pattern
When you create a promise with new Promise and want it to resolve some time later, then you could indeed use setTimeout, but then the idea is to call resolve only when that timer has expired. Otherwise the timer does not do anything that serves the promise:
setTimeout(() => {
resolve();
}, 0);
I am trying to write logic in JS to stop function execution abruptly (without executing further) when in call sequence. Check below code. Why isn't stopping after second call?
function myprom (value) {
return new Promise (function (resolve, reject) {
resolve("I Promise " + value)
})
}
function myfunc (value) {
console.log("Starting in " + value)
}
function terminate() {
setTimeout(() => console.log("Edning"), 1)
}
function dummy() {
console.log("I am not supposed to print anything")
}
async function call() {
await myprom("to end without showing next line")
.then(result => {
myfunc(1) // Call # 1
console.log(result) // Call # 2
terminate() // Call # 3
dummy(1) // Call # 4
terminate() // Call # 5
})
.catch(err => {
console.log(err)
})
}
call()
Below is the actual output of my code.
Starting in 1
I Promise to end without showing next line
I am not supposed to print anything
Ending
Ending
What is expected is,
Starting in 1
I Promise to end without showing next line
Ending
In general. how to stop js execution abruptly inside .then object?
When you call this terminate() which is this:
function terminate() {
setTimeout(() => console.log("Edning"), 1)
}
The setTimeout() pushes it's callback to a future cycle of the event loop and EVERYTHING else in the current cycle of the event loop runs before it. Only when the current chain of code has finished and control has returned back to the event loop will the setTimeout() get a chance to run its callback.
So, here's the sequence of what happens in your code:
call() is executed.
myprom() is executed. That resolves its promise immediately so it will schedule it's .then() handlers to run as soon as control returns back to the event loop.
.then() and .catch() run. All they do at this point is register some callbacks to be called later when the promise is ready to execute them.
Your async function returns and control goes back to the event loop.
The already resolved promise is first in line in the event loop so it gets control and executes it's .then() handler.
myfunc(1) runs and that outputs Starting in 1
console.log(result) runs and that outputs I Promise to end without showing next line
terminate() runs and that sets a timer for 1ms from now. That function returns and the timer is schedule to run on a future tick of the event loop when 1ms has passed.
dummy(1) is called and that outputs I am not supposed to print anything.
terminate() is called again and that again schedules another timer to run in 1ms on a future tick of the event loop.
The await processes the promise and resolves the promise that the async function call() returns. The await does nothing useful here and there's nothing listening for the promise that call() returns either.
Control is returned back to the event loop.
The first timer you set with the first call to terminate() gets to run and it outputs. That returns control back to the event loop.
The second timer you set with the second call to terminate() gets to run and it puts. That returns control back to the event loop and everything associated with this code is done.
In general. how to stop js execution abruptly inside .then object?
If what you're asking is how you skip the other functions you call all in a row, then you would typically use conditionals to branch of return early out of the .then() callback. For example, you could do this:
async function call() {
await myprom("to end without showing next line")
.then(result => {
myfunc(1) // Call # 1
console.log(result) // Call # 2
if (result === "I Promise to end without showing next line") {
// skip the rest of the code in this callback
return;
}
terminate() // Call # 3
dummy(1) // Call # 4
terminate() // Call # 5
})
.catch(err => {
console.log(err)
})
}
call()
Since you're in a .then() handler, you could also so a throw someError and that would abruptly stop the .then() handler just like throwing any exception aborts the execution of the current function. Because this is in a .then() handler that exception will be immediately caught and will then execute the .catch() handler and pass it the exception you threw. This wouldn't typically be used for a normal execution path because this more typically indicates some error condition. A normal execution path would more likely catch the condition locally and use branching or if/else logic or something like that to decide what code in the function executes next.
Note, if you've already started some timers, then to keep them from firing, you would have to save the timerID that setTimeout() returned and use clearTimeout() on that timerID to cancel the timer.
If you really want abrupt stopping to stop your whole process, then in node.js, you can also call process.exit().
It's unclear why you thought the output from dummy(1) and the second call to terminate() would not show in the output? You called dummy(1). Nothing in the terminate() function causes Javascript to skip the rest of the code in the .then() handler. So, it continues and executes both dummy(1) and the second terminate() and thus you see the output from both.
Instead of calling terminate you could use return. That would solve your purpose.
The function terminate does not stop the execution of the function but instead schedules a function to run later with a timeout of at least 1 second. So, the function should instead be called delay. I have added a Promise based implementation of the same:
function delay(time = 1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Ending');
resolve();
}, time);
})
}
A function returning a scalar value can be awaited. So, there is no need to wrap myProm using the Promise constructor. Assuming that myprom is a real async operation instead of a function returning a string, of course.
function myprom (value) {
return `I Promise ${value}`;
}
When using async functions, the callback with .then and .catch is not necessary.
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1)
} catch (e) {
console.error(e);
}
}
The existing code snippet with the changes would look like this:
// scalar values can be resolved too
function myprom (value) {
return `I Promise ${value}`;
}
function myfunc (value) {
console.log("Starting in " + value)
}
function delay(time = 1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Ending');
resolve();
}, time);
})
}
function dummy() {
console.log("I am not supposed to print anything")
}
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1)
await delay();
dummy(1);
await delay();
} catch (e) {
console.error(e);
}
return undefined;
}
call();
However, as explained this will not stop the flow of execution:
myprom runs
result is printed
myFunc executes
after a delay of 1 second, a message of Ending prints (because the event loop is not blocked by many async operations)
dummy executes
after a delay of 1 second, a message of Ending prints
the function returns a Promise that resolves to a value of undefined.
Instead of using delay, we can use return when we need to terminate the execution of the function:
function myprom(value) {
return `I Promise ${value}`;
}
function myfunc(value) {
console.log("Starting in " + value)
}
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1);
return
} catch (e) {
console.error(e);
}
}
call();
This question already has answers here:
Why is the method executed immediately when I use setTimeout?
(8 answers)
How to turn this callback into a promise using async/await?
(2 answers)
Closed 3 years ago.
I already posted a question on this subject here on StackOverflow. Following the recommendations, I have tried to simplify my question.
I don't understand how to make synchronous code with Promises and their new polished version using async/await, despite the fact I have read and tried different approaches.
Here, I link some good documentation on the subject, in case it can help people in the future. Basically, Promises are an answer to callback hell and a way to make code execute after some other code has been executed, making things happening synchronously since JavaScript (hence Node.js) is asynchronous by nature. Async/await is built on top of Promises and simplify the code.
understanding JavaScript Promises
modern JavaScript with async/await
Async/await explained with examples
why moving from Promises to async/await
Despite I seem to understand the concept, I can't explain the results I obtain. To better my comprehension, here is a test file using node.js -v v8.10.0
/* This file try to use Promises and async/await to run code synchronously */
/* declaration of some Promisified functions */
const doSomethingAsync = () => { // direct declaration using new Promise and Promise.resolve()
return new Promise(resolve => { // This is just a promise, necesiry to wait for it
setTimeout(() => resolve('I want to be first'), 3000);
});
};
const test1 = async () => { // indirect Promise declaration usind async
return setTimeout(() => console.log("test1, I want to be executed first"), 3000); // async => the function returns a promise hence return a resolve,
}; // we should use await to wait for the Promise.resolve()
/* create intermediate calling functions making code synchronous to use console.log() properly */
const doSomething = async () => {
console.log( await doSomethingAsync());
};
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
await test1();
console.log("hope to be executed after test1() resolve");
}
/* hope to run code synchronously in the following using .then() keyword */
console.log('1');
doSomething();
console.log('2');
callTest();
console.log('3');
doSomething()
.then(console.log("I want to be after"))
.catch(error =>{
console.log(error);
});
console.log('4');
console.log( doSomethingAsync().then(console.log("I want to be after too")) );
console.log('5');
// hope to run code synchronously in the following using await keyword
(async () => {
let test2 = await doSomethingAsync();
let test3 = await doSomething();
await test1();
console.log(`value doSomethingAsync: ${test2}`);
console.log(`value doSomething: ${test3}`);
})();
console.log('6');
What I expect is to see the code putted into the .then() keyword to be executed synchronously after Promise.resolve() fire... but it's not what I observe. See below the output of the program in my terminal:
ʘ node test_promises.js
1
2
hope to be executed before test1() resolve
3
I want to be after
4
I want to be after too
Promise { <pending> }
5
6
hope to be executed after test1() resolve
test1, I want to be executed first
I want to be first
I want to be first
I want to be first
value doSomethingAsync: I want to be first
value doSomething: undefined
test1, I want to be executed first
From the output, it is clear that .then() runs before the code inside the called function.
from StackOverflow
The success or the error handler in the then function will be called only once, after the asynchronous task finishes.
It seems not to be the case. Hence my question is straightforward:
Question: Why is .then() called before the asynchronous tack finish, and how to properly code with Promises, .then() and async/await (which is supposed to replace then)?
EDIT
From the answer of the community, I understand that .then() fires directly when the values passed to it are not callback functions. Hence, by modifying the .then() like so .then(function() {console.log("I want to be after")} )
Ok, I had not understood. I get
ʘ node test_promises.js
1
2
hope to be executed before test1() resolve
3
4
Promise { <pending> }
5
6
hope to be executed after test1() resolve
test1, I want to be executed first
I want to be after too
I want to be first
I want to be first
I want to be after
I want to be first
value doSomethingAsync: I want to be first
value doSomething: undefined
test1, I want to be executed first
I still do not understand why the console.log()s fire before the await function call in
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
await test1();
console.log("hope to be executed after test1() resolve");
}
Thanks for the patience of the community
EDIT 2
From the answers of the community:
An async function only waits for the things that are awaited inside
its code. It does not automagically recognise any calls that do
something asynchronous. You need to explicitly promisify setTimeout
to make it work with promises. – Bergi ANSWER 2: return setTimeout(()
=> console.log("test1, I want to be executed first"), 3000) isn’t correct, because setTimeout doesn’t return a promise. Converting
functions that use callbacks, like setTimeout, without using other
helper functions is a little wordy: return new Promise(resolve => {
setTimeout(resolve, 3000); }); – Ry-♦
This means the correct code is the following:
// declaration of some Promisified functions
const doSomethingAsync = () => {
return new Promise(resolve => {
setTimeout(() => resolve('I want to be first'), 3000);
});
};
const test1 = async () => { // IMPORTANT CORRECTION: use Promise constructor
return new Promise(resolve => { setTimeout( () => {resolve("test1, I want to be executed first")}, 3000); }); // actuallu async do not transform the return
}; // function into a Promise
// create intermediate calling functions making code synchronous to use console.log() properly
const doSomething = async () => {
console.log( await doSomethingAsync());
};
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
const resultTest1 = await test1(); // IMPORTANT CORRECTION: declare a variable to return the value of the executed function when exec is over, using await
console.log(resultTest1);
console.log("hope to be executed after test1() resolve");
}
// hope to run code synchronously in the following using .then() keyword
console.log('1');
doSomething();
console.log('2');
callTest();
console.log('3');
doSomething()
.then(function() {console.log("I want to be after")} ) // IMPORTANT CORRECTION: declare a callback function instead of executing the function
.catch(error =>{
console.log(error);
});
console.log('4');
console.log( doSomethingAsync().then(function() {console.log("I want to be after too")}) );
console.log('5');
// hope to run code synchronously in the following using await keyword, THIS IS THE "RIGHT" WAY TO USE ASYNC/AWAIT
(async () => {
let test2 = await doSomethingAsync();
let test3 = await doSomething();
await test1(); // this is the last await, it will be the last executed code
console.log(`value doSomethingAsync: ${test2}`);
console.log(`value doSomething: ${test3}`);
})();
console.log('6');
A special thank to everyone that helped. I hope this will be useful.
I have a simple code in JavaScript that execute a request in an API and return the response, simple. But in this case I will have thousands of requests. So, which one of the code options will perform better, and why. Also which one is recommended as good pratices these days?
First options is using the .then to resolve the promises and the seccond one is using async / await.
In my tests the two options had very similar results without significant differences, but I'm not sure in scale.
// Using then
doSomething(payload) {
const url = 'https://link-here/consultas';
return this.axios.get(url, {
params: {
token: payload.token,
chave: payload.chave,
},
}).then(resp => resp.data);
}
// Using Async / await
async doSomething(payload) {
const url = 'https://link-here/consultas';
const resp = await this.axios.get(url, {
params: {
token: payload.token,
chave: payload.chave,
},
});
return resp.data;
}
Any explanation will be of great value.
From a performance point of view, await is just an internal version of .then() (doing basically the same thing). The reason to choose one over the other doesn't really have to do with performance, but has to do with desired coding style or coding convenience. Certainly, the interpreter has a few more opportunities to optimize things internally with await, but its unlikely that should be how you decide which to use. If all else was equal, I would choose await for the reason cited above. But, I'd first choose which made the code simpler to write and understand and maintain and test.
Used properly, await can often save you a bunch of lines of code making your code simpler to read, test and maintain. That's why it was invented.
There's no meaningful difference between the two versions of your code. Both achieve the same result when the axios call is successful or has an error.
Where await could make more of a convenience difference is if you had multiple successive asynchronous calls that needed to be serialized. Then, rather than bracketing them each inside a .then() handler to chain them properly, you could just use await and have simpler looking code.
A common mistake with both await and .then() is to forget proper error handling. If your error handling desire in this function is to just return the rejected promise, then both of your versions do that identically. But, if you have multiple async calls in a row and you want to do anything more complex than just returning the first rejection, then the error handling techniques for await and .then()/.catch() are quite different and which seems simpler will depend upon the situation.
There should be some corrections in this thread. await and .then are going to give very different results, and should be used for different reasons.
await will WAIT for something, and then continue to the next line. It's also the simpler of the two because it behaves mechanically more like synchronous behavior. You do step #1, wait, and then continue.
console.log("Runs first.");
await SomeFunction();
console.log("Runs last.");
.then splits off from the original call and starts operating within its own scope, and will update at a time the original scope cannot predict. If we can put semantics aside for a moment, it's "more asynchronous," because it leaves the old scope and branches off into a new one.
console.log("Runs first.");
SomeFunction().then((value) => {console.log("Runs last (probably). Didn't use await on SomeFunction().")})
console.log("Runs second (probably).");
As more explanation to #user280209 answer let's consider the following function which returns promise and compare its execution with .then() and async await.
function call(timeout) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`This call took ${timeout} seconds`);
resolve(true);
}, timeout * 1000);
});
}
With .then()
(async () => {
call(5).then((r) => {
console.log(r);
});
await call(2); //This will print result first
await call(1);
})();
When running the above call the logs will be
This call took 2 seconds
This call took 1 seconds
This call took 5 seconds
true
As we can see .then() didn't pause the execution of its below line until it completes.
With async/wait
(async () => {
await call(5); //This will print result first
await call(2);
await call(1);
})();
When run the above function logs will be
This call took 5 seconds
This call took 2 seconds
This call took 1 seconds
So I think if your promise's result won't be used in the following lines, .then() may be better.
For those saying await blocks the code until the async call returns you are missing the point. "await" is syntactic sugar for a promise.then(). It is effectively wrapping the rest of your function in the then block of a promise it is creating for you. There is no real "blocking" or "waiting".
run();
async function run() {
console.log('running');
makePromises();
console.log('exiting right away!');
}
async function makePromises() {
console.log('make promise 1');
const myPromise = promiseMe(1)
.then(msg => {
console.log(`What i want to run after the promise is resolved ${msg}`)
})
console.log('make promise 2')
const msg = await promiseMe(2);
console.log(`What i want to run after the promise is resolved via await ${msg}`)
}
function promiseMe(num: number): Promise<string> {
return new Promise((resolve, reject) => {
console.log(`promise`)
resolve(`hello promise ${num}`);
})
}
The await line in makePromises does not block anything and the output is:
running
make promise 1
promise
make promise 2
promise
exiting right away!
What i want to run after the promise is resolved hello promise 1
What i want to run after the promise is resolved via await hello promise 2
Actually.
Await/Async can perform more efficiently as Promise.then() loses the scope in which it was called after execution, you are attaching a callback to the callback stack.
What it causes is: The system now has to store a reference to where the .then() was called. In case of error it has to correctly point to where the error happens, otherwise, without the scope (as the system resumed execution after called the Promise, waiting to comeback to the .then() later) it isn't able to point to where the error happened.
Async/Await you suspend the exection of the method where it is being called thus preserving reference.
If we just consider performance(time taken) then it actually depends on whether your operations are serial or parallel. If your tasks are serial then there will be no difference between await and .then. But if your tasks are parallel then .then will take less time. Consider the following example
let time = Date.now();
// first task takes 1.5 secs
async function firstTask () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
},1500)
})
}
// second task takes 2 secs
async function secondTask () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
},2000)
})
}
// using await
async function call(){
const d1 = await firstTask();
const d2 = await secondTask();
console.log(Date.now()-time, d1+d2)
}
call()
// using .then
async function call2(){
let d1=null,d2=null;
firstTask().then(data => {
d1=data;
if(d2){
console.log(Date.now()-time, d1+d2);
}
})
secondTask().then(data => {
d2=data;
if(d1){
console.log(Date.now()-time, d1+d2);
}
})
}
call2()
Here are the two tasks, first takes 1.5 secs and second takes 2 secs. Call function uses await where as call2 function uses .then . The output is as follows
From call2 2012 3
From call 3506 3
I hope it helps.
As far as I understand .then() and await are not the same thing. An async function won't proceed with the next command until the promise is resolved/rejected since it's basically an implementation of generators. On the contrast, in the case of .then(), the execution of the function will proceed with the next command and the resolve/reject callback will be executed "when there's time" aka when the current event loop (not entirely sure about that part) will be completed.
tldr; on a single promise await and .then() behave similarly but when one promise needs another one to be resolved first then the two of them behave entirely different
Many answer have been provided to this question already. However, to point out key information in the answers above and from my understanding, note below point:
only use await when not handling error return
if no crucial need for error handling use await instead
use .then .catch if returned error message or data is crucial for debugging / or proper error handling instead of try catch for await
Choose any prefer method from code sample below
const getData = (params = {name: 'john', email: 'ex#gmail.com'}) => {
return axios.post(url, params);
}
// anywhere you want to get the return data
// using await
const setData = async () => {
const data = await getData();
}
// to handle error with await
const setData = async () => {
try {
const data = await getData();
}
catch(err) {
console.log(err.message);
}
}
// using .then .catch
const setData = () => {
var data;
getData().then((res) => {
data = res.data; console.log(data)
}).catch((err) => {
console.log(err.message);
});
}
I'm trying to get a loop working with a longer delay, when the task takes longer as planned.
currently I'm using this code for the loop:
async function doSomeStuff() {
// do some stuff
// sometimes this action may take longer than 5 seconds
// after finishing wait 5 seconds
console.log('task completed, waiting 5 seconds for next run...');
}
setInterval(doSomeStuff, 5000);
works like a charm, but the delay is fixed at 5 seconds, even if the tasks takes longer as planned, so that sometimes the new loop starts only 1 second after finishing the last one instead of waiting 5 seconds.
unfortunately, I was not able to solve it myself by looking at the other questions.
I am grateful for any help.
Best regards
Paedda
async functions shouldn't be used with API that ignores a promise that it returns such as setInterval, in case it's expected that a promise should be chained.
This can be done with recursive async function:
(async function doSomeStuff() {
await new Promise(resolve => setTimeout(resolve, 5000));
// do some stuff
await doSomeStuff();
})();
Or infinite loop:
(async function doSomeStuff() {
while (true) {
await new Promise(resolve => setTimeout(resolve, 5000));
// do some stuff
}
})();
Function body can be wrapped with try..catch if needed to handle errors.
You were almost there
async function doSomeStuff() {
// do some stuff
// sometimes this action may take longer than 5 seconds
// after finishing wait 5 seconds
console.log('task completed, waiting 5 seconds for next run...');
setTimeout(doSomeStuff, 5000);
}