This question already has answers here:
Are JavaScript Promise asynchronous?
(3 answers)
When does async function actually return a pending promise?
(1 answer)
Do Javascript promises block the stack
(4 answers)
What are asynchronous functions in JavaScript? What is "async" and "await" in JavaScript?
(2 answers)
Closed last year.
Every single example I read about it has code demonstrations that are synchronously executed, with the article writers pretending they're asynchronous.
No example I've seen yet says the code keeps running past the 'asynchronous' promise. If the code kept running while the promise was fulfilled, or the await was taking place, then it could be called asynchonous.
But if the main line of code stops for the promise/await response, then it's simply synchronous.
Can anyone explain this? I had the impression that code ran past the promise/sync function, rather than stopping and 'awaiting' the result to then continue the rest of the code identically to a normal synchronous execution operation.
Promises themselves aren't really asynchronous. They are a pattern to implement working with other things that themselves are asynchronous.
Just like a callback is just a function, we tend to call them 'callbacks' if they get triggered at a later point.
All a Promise really is for is encapsulating the status of an asynchronous operation and let people access the result.
Asterisk: Promises themselves are also a little asynchronous, because they guarantee that the function passed to then() always happens at least in the next tick if the result already arrived.
And await doesn't block the process, it literally pauses the function and lets other things run. Similar to yield, which is also not asynchronous by itself.
Promises register callbacks for further execution when they resolve:
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
test.then(() => console.log('Resolved'));
console.log('End');
Now if you think this is synchronous code:
(async function() {
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
await test;
console.log('Resolved');
console.log('End');
})();
Well it's not, it's actually an equivalent of:
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
test.then(() => {
console.log('Resolved');
console.log('End');
});
Conclusion: when you await a Promise you just use syntactic sugar. Really nice syntactic sugar that prevents callback hell:
The call stack unwinds and frees the event loop with async/await, just like it would with callbacks, making the event loop available for other code execution until the Promise resolves.
Related
So, I am currently learning about callbacks and promises and I keep getting tripped up when watching tutorials. So i thought that I would put it in an example form and see if anyone could tell me if my thinking is correct. I am currently working with MongoDB and Mongoose.
Here is an example piece of code taken from a tutorial. I believe that this is considered a callback?
user.save((err) => {
if (err) {
return res.status(400).json({
error: "You are not authorized to perform this action.",
})
});
And then this would be considered a promise?
user.save().catch(err => {
return res.status(400).json({
error: "You are not authorized."
})
})
Are there any performance advantages of using a promise over a callback or vice versa?
Thank You!
Callbacks and promises are different but share some concepts.
A callback is simply a function passed to another function as a parameter where that function can be executed at any time.
for example:
function iNeedACallback(callback)
{
// execute a bunch of code...
// use the callback function provided
callBack("a function called 'iNeedACallback'")
}
const callback = (fromFunction) => console.log("I am a callback function called from: " + fromFunction);
// Execute iNeedACallback by passing in the callback
iNeedACallback(callback);
The above code is a very simplistic instance of a callback function - now this can either be executed sequentially(like in the example above) or it can be an async operation on the event loop. (for more info about the event loop: Why do you need to await AJAX calls in JS but not in C#?)
A Promise makes use of callback functions in order to handle async code in a conventional way. The nature of a Promise infers that its some code that will be placed on the event loop as it executed asynchronously and not block any other code while waiting for an operation like a network call.
for example:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const text = "i was only called after 2 seconds :(";
resolve(text);
}, 2000)
})
promise.then((text) => console.log(text))
console.log("i got called immediately :)")
//Output:
//i got called immediately :)
//i was only called after 2 seconds :(
In the above example we give a promise a callback function to execute when an async operation has completed (like a setTimeout) where the most common use cases are network calls like HTTP requests or TCP connections to a database like mongodb.
Back to your original question - your assumption is correct in the sense that your demonstration of a callback and promise is correct, and your question about performance..
Javascript is single threaded so if your callback function is placed on the event loop (which it may or may not be) then it will not block the main execution call stack. Promises are inherently async operation so they will always be placed on the event loop so the performance factor is dependent on the underlying implementation of the callback function - Promises will be async where as some regular callbacks could be sequential and synchronous.
This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 4 years ago.
I don't understand how to work with asynchronous functions.
Why does the code below stop the main thread?
async function foo() {
for (;;) {}
}
foo();
The async keyword, and promises in general, don't make synchronous code asynchronous, slow running code fast, or blocking code non-blocking.
async just makes the function return a promise and provides (with the await keyword) a mechanism to interact with other promises as if there were synchronous.
Your function starts a loop, and then just goes around and around.
It doesn't get to the end of the function, which would end the function and resolve the promise it returned.
It doesn't reach an await keyword and pause while it waits for the awaited promise to be resolved.
It just goes around and around.
If you were actually doing something in the loop which was computationally expensive and you wanted to push off into the background, then you could use a Node.js Worker Thread or a browser-based Web Worker to do it.
Putting the async keyword before the function only implies that this is asynchronous function. You need to include the keyword await before the function that you want to actually wait for. Just like this:
async function hashPin(pin){
const hashedPin = await bcrypt.hash(pin, saltRounds);
}
That's just the example from one of my projects (the redundant code has been removed before posting)
This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 4 years ago.
I don't understand how to work with asynchronous functions.
Why does the code below stop the main thread?
async function foo() {
for (;;) {}
}
foo();
The async keyword, and promises in general, don't make synchronous code asynchronous, slow running code fast, or blocking code non-blocking.
async just makes the function return a promise and provides (with the await keyword) a mechanism to interact with other promises as if there were synchronous.
Your function starts a loop, and then just goes around and around.
It doesn't get to the end of the function, which would end the function and resolve the promise it returned.
It doesn't reach an await keyword and pause while it waits for the awaited promise to be resolved.
It just goes around and around.
If you were actually doing something in the loop which was computationally expensive and you wanted to push off into the background, then you could use a Node.js Worker Thread or a browser-based Web Worker to do it.
Putting the async keyword before the function only implies that this is asynchronous function. You need to include the keyword await before the function that you want to actually wait for. Just like this:
async function hashPin(pin){
const hashedPin = await bcrypt.hash(pin, saltRounds);
}
That's just the example from one of my projects (the redundant code has been removed before posting)
This question already has answers here:
Will async/await block a thread node.js
(6 answers)
Closed 3 years ago.
I have two functions, the first is the main function which has switch statement calling the second which is async. If my second function is async isn't that non-blocking? Would I still have to make the first one async in order for it to be non-blocking, if so why?
Example
exports.funcOne = async (theParam) => { // async ??
switch (theParam) {
case 'hey':
return await funcTwo()
default:
...
}
}
const funcTwo = async () => {
await axios.get...
}
Second function can just return the promise :
exports.funcOne = async (theParam) => { // async ??
switch (theParam) {
case 'hey':
const myData = await funcTwo();
console.log("response from request : ", myData);
//do something with data
default:
...
}
}
const funcTwo = () => {
//axios.get is a promise, so is the return type for funcTwo
return axios.get...
}
Calling an AsyncFunction returns a Promise. As Eric said you could return the Promise in the funcTwo and it doesnt need to be an AsyncFunction because it is secuential and it is in the functionOne thread. So if you return the Promise in the functionTwo, the result of the Promise "axios.get..." will be resolved in "return await funcTwo()" in the functionOne.
In general, all functions that contain await must be async.
That rule might make more sense if we imagine it would not exist, and if you could wait for an asynchronous result in a synchronous function.
First of all, we need to know one important things about functions:
They have to run to completion, or in other words: A regular function runs till it's return and no other code can run at the same time.
If we could await inside of a non-async function that would mean that we would block execution until the awaited promise resolves, as no other code can run in the meantime. As the code that resolves the promise also cannot run, we created a deadlock.
async functions only run to completion till they reach an await. Therefore, when axios.get(...) gets called, a promise gets returned synchronously from it, funcTwo halts execution, returns a promise itself, therefore funcOne also halts execution (thats possible cause it's async). Then the engine can continue with other stuff, and somewhen when the underlying request is done, the promise resolves, funcTwo continues execution which resolves the promise it returned, funcOne continues execution and resolves the returned promise too.
If my second function is async isn't that non-blocking?
That really depends on your definition of non-blocking. In general, every code of JS that executes kind of "blocks the thread" (as only one function can execute at a time), but as most tasks are very small, you won't notice that blocking.
An asnyc function is also blocking, as long as it doesn't halt for a promise to resolve. Then it is in a non-blocking waiting state.
Asynchronous tasks (e.g. doing a network request) also aren't blocking, cause they are handled by the engine (offloaded to other threads or hardware, etc.).
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 4 years ago.
I have a batch script written in JS, executed under Node.
This is a very linear, logically synchronous batch script -- Thing A has to happen before Thing B, etc. This thing needs to execute from top to bottom, ideally line by line, synchronously.
(Performance is not that important here. The execution time would be 30 seconds, worst case. Additionally, there's no UI to lock up while the code blocks. This will only ever be run in batch from the command line, and I'll probably be watching it execute every time.)
I've been working through various options:
the "async" npm module
writing my own Promises
using async and await
I really like the last one, just from an understandability standpoint. It "degrades" JavaScript to simple, linear execution, which is frankly what I want.
go()
async function go() {
await doThingOne()
await doThingTwo()
}
However, sometimes I have code inside my methods which comes from third-party modules, and is asynchronous with no synchronous option.
Consider:
go()
async function go() {
await doThingOne()
await doThingTwo()
}
function doThingOne() {
// do some things here
doAsyncThingFromExternalLibrary()
// do some more things here
}
How do I await that third-party call? It's written asynchronously, has no synchronous option, and is not code that I would want to change.
Is there a way to "wrap" that call so the code stops and waits for it? Should I wrap it in my own Promise and make it thenable?
What's the best way to do this?
Is there a way to "wrap" that call so the code stops and waits for it? Should I wrap it in my own Promise and make it thenable?
Yes.
await will await a promise, so if you have a function that you want to await then you need it to return a promise.
Same way you would do for your own code.
(async function() {
await doThingOne();
await doThingTwo();
const result = await new Promise((resolve, reject) => {
doAsyncThingFromExternalLibrary(function(err, result) {
if (err) return reject(err);
resolve(result);
});
});
})();
function doThingOne() {
return Promise.resolve();
}
function doThingTwo() {
return Promise.resolve();
}
function doAsyncThingFromExternalLibrary(fn) {
setTimeout(fn, 1000);
}