This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 27 days ago.
I just wonder if there is different between those 2 calls by await Promise.all([/* ... /*])
In my performance test, it took the same time.
This is my method to be invoked by the Promise.all:
const makeFetch1 = async () => {
axios.get("https://jsonplaceholder.typicode.com/todos/1");
};
const makeFetch2 = async () => {
return axios.get("https://jsonplaceholder.typicode.com/todos/1");
};
1) await Promise.all([makeFetch1(), makeFetch1(), ...])
2) await Promise.all([makeFetch2(), makeFetch2(), ...])
Both have the same execution time result, what i should choose?
The first one will fire of a request and not return it. so makeFetch1() will result in a Promise that resolves immediately. This is almost certainly never what you want. An async function should await or return inside somewhere, otherwise it may as well be a standard function (that returns nothing).
Even if you don't care about what the request resolves to, you should still use the result of the request (by returning or awaiting, just so you can see if the request succeeds or not - and communicate to the user that there was a problem if it fails)
The second one will fire of a request and return it. so makeFetch1() will result in a Promise that resolves once the request resolves - which is likely to take a number of milliseconds.
There are several major differences and multiple coding mistakes.
First off this code:
const makeFetch1 = async () => {
axios.get("https://jsonplaceholder.typicode.com/todos/1");
};
is an async function that calls axios.get() and then immediately returns a promise that is already resolved and has an undefined resolved value. Nothing here waits for the axios.get() call to finish.
Your second code block:
const makeFetch2 = async () => {
return axios.get("https://jsonplaceholder.typicode.com/todos/1");
};
calls axios.get() and returns the promise that it creates. So, the promise this function returns will be tied to when the axios.get() call completes and the resolved value will be the resolved value of the axios call.
Differences:
You could use the makeFetch2() function to get the result of the axios.get() call (resolved value or reject error). You could not use makeFetch1() to get the result of the axios.get() call because that result is not communicated back to the caller in any way.
Similarly, makeFetch2() will allow the caller to know when the axios operation has completed. makeFetch1() will not.
If the axios.get() operation rejected, then makeFetch1() would result in an unhandled rejection error because nothing is listening for the rejection.
Then, these two:
await Promise.all([makeFetch1, makeFetch1, ...])
await Promise.all([makeFetch2, makeFetch2, ...])
Are both pretty useless because you're not calling any of the functions so nothing is executing. These will both just resolve immediately with a resolved value of an array of function references. None of the axios calls are executed because nothing actually calls makeFetch1() or makeFetch2().
If you meant to actually execute the functions with these two:
await Promise.all([makeFetch1(), makeFetch1(), ...])
await Promise.all([makeFetch2(), makeFetch2(), ...])
Then, the first one just resolves immediately with an array of undefined values as the resolved value because remember the makeFetch1() return value isn't connected in any way to the axios.get() call.
The second one will properly wait for all the axios.get() calls in makeFetch2() to complete and will resolve with an array of values from the axios.get() calls.
Both have the same execution time result, what i should choose?
That's because as you've implemented them, you aren't calling the makeFetchN() functions in either case. So, they aren't doing anything and thus have the same execution time.
If you change the implementation to actually call the functions as in:
await Promise.all([makeFetch1(), makeFetch1(), ...])
await Promise.all([makeFetch2(), makeFetch2(), ...])
There will be a significant timing difference because the one based on makeFetch1() does not wait for any of the axios.get() calls to finish and does not communicate back results or completion and is subject to uncaught rejections.
The one based on makeFetch1() has no practical use as you could just do:
makeFetch1();
makeFetch1();
...
with the exact same result because makeFetch1() just returns an immediately resolved promise so passing them all to Promise.all() isn't doing anything useful.
makeFetch1() is probably just not useful since it doesn't inform the caller of completion, error or resolved value.
Related
I thought I understood how to use async and await till I saw the below code snippet.
So there is an onInput event handler function attached to the movie input textbox. Within it is called the fetchData asynchronous function which uses the await keyword to wait for results from the axios.get function.
My question is, why do we need to make the onInput function also async? I mean, the fetchData function is async. Which means, it will wait till the axios.get is resolved and the execution will be paused till axios.get is resolved. So when the line const movies = fetchData(event.target.value); executes, the fetchData function will be executed which will pause on the await axios.get statement. So why do we need to use await while calling fetchData and make onInput async??
const fetchData = async(searchTerm)=>{
const results = await axios.get('http://www.omdbapi.com/', {
params:{
apikey:'d9835cc5',
s: searchTerm
}
});
return results.data.Search;
}
const movieInput = document.querySelector('input');
const onInput = async event => {
const movies = await fetchData(event.target.value);
console.log(movies);
}
movieInput.addEventListener('input', onInput);
I mean, the fetchData function is async. Which means, it will wait till the axios.get is resolved and the execution will be paused till axios.get is resolved.
This concept is hiding a lot of detail that may be confusing, such as that paused execution is resumed using callback functions.
async functions do not pause execution of their callers.
Instead they return a promise that will be resolved with the value syntactically returned from executing the async function body. To be clear, the value apparently returned from within an async function body is not returned to the caller directly - the caller gets a promise for it.
When executed the await operator sets up call backs for when its operand promise becomes settled. Effectively it calls the then method of its promise operand to supply a set of onfulfilled and onrejected callbacks, before storing the current execution context in memory and returning to the event loop.
When it receives a callback from promise settlement, the await operator restores the execution context it previously saved. If the awaited promise is rejected, await throws the rejection reason. If fulfilled, await resumes exection and returns the fulfilled value of the promise as the result of executing the await operator.
Now historically await was never a reserved keyword - not mentioned in ES3, future reserved keyword in ES6 (ECMAScript 2015) but reserved word in the current draft of ECMAscript as at May 2021.
Hence, to retain compatibility with code on the web, await was only recognized as an operator if it occurs within an async function - leaving it available as an identifier outside of async function bodies.
Likewise the async keyword was not historically reserved, but was able to be introduced without comparability issues by requiring its usage in a position that would have produced an unexpected identifier error in previous versions of JavaScript. Meaning before the function keyword or before an arrow function expression.
Finally you need to declare onInput as an async function because await is being used as an operator within its body. Without the async declaraton, await will be treated as an identifier rather than the name of an operator.
As a side note, the promise returned by onInput is being discarded and could generate an uncaught promise rejection error in its current form.
To answer the slightly different question of "why does await need to be used in the onInput function at all?", the value returned from fetchData is a pending promise. In order to set movies to the results.data.Search value obtained within fetchData, you need to wait for the fulfilled value of the returned promise. Using async/await is one means of doing so. The other is to add a fulfillment handler to the promise returned from fetchData by calling its then method.
You are using the await operator inside inInput. It's a JavaScript rule that functions using await must be async, so inInput must also be async. Have a look at this answer: https://stackoverflow.com/a/56685416/13357440
Also, MDN has useful information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
In general, you would want API calls to execute while the rest of your program runs, so the onInput would be async. Furthermore, javascript mandates that an await is inside of an async function, so the code was simply following its standards and rules as well. Typically, once the top level is an async, everything inside of it is just following the structure. More info can be found here.
I'm pretty new to JavaScript (using Node.js) and still learning. I try to wrap around my head with promises and I got into this situation where I don't understand if there is a difference between this code:
promiseFunc().then(() => {
anotherPromiseFunc() // I dont need .then() here, just want to save some data to DB
});
doSmthElse()
and this code:
promiseFunc().then(async () => {
await anotherPromiseFunc() // I dont need .then() here, just want to save some data to DB
});
doSmthElse()
If I don't use .then() in the first case, does it mean there is a possibility that doSmthElse() will be executed before anotherPromiseFunc() is executed? So in order to prevent that, I have to add async/await? Or all code in .then() block is being waited to execute anyway before doing something else?
Note 1: I don't want to chain those promises, because there is more code in my case, but I just simplified it here.
Note 2: I don't use catch because if error will rip through I will catch it later.
If I don't use .then() in the first case, does it mean there is a possibility that doSmthElse() will be executed before AnotherPromise() is executed?
doSmthElse() is guaranteed to be executed before anything in the fulfillment handler¹ is executed. Promise fulfillment and rejection handlers are always invoked asynchronously. That's true whether you declare the handler function using async or not.
For example:
console.log("before");
Promise.resolve(42)
.then(result => {
console.log("within", result);
});
console.log("after");
The output of that is:
before
after
within 42
So in order to prevent that, I have to add async/await?
Where you've added async/await in your example doesn't change when doSmthElse() is executed.
If you want doSmthElse() to wait until the promise has been fulfilled, move it into the fulfillment handler.¹
If your code were inside an async function, you could use await instead, like this:
// Inside an `async` function
await promiseFunc().then(() => {
anotherPromiseFunc();
});
doSmthElse()
That would do this:
Call promiseFunc() and get the promise it returns
Hook up a fulfillment handler to that promise via then, returning a new promise; that new promise is the operand to await
Wait for the promise from #1 to settle
When it does, your fulfillment handler is executed and runs anothterPromiseFunc() but doesn't wait for the promise it returns to settle (because, as you said, you're not returning that promise from the fulfillment handler).
At this point, the promise from #2 is fulfilled because your fulfillment handler has (effectively) returned undefined, which isn't a thenable (loosely, a promise), so that value (undefined) is used to fulfill the promise from #2.
Since the promise from #2 has been fulfilled, await is satisfied and doSmthElse() is executed.
¹ the function you pass then as its first argument
I assume that Promise() just stands for some function call returning a Promise:
You could say that .then registers an event listener that runs as soon as the promise settles => the task is finished. It still runs asynchronously So in your example doSmthElse will still run even if the promise hasn't been settled (so if the promise doesn't settle immediately doSmthElse will be called before the function inside .then)
To let your code run "in order". You would have to use await to ensure that doSmthElse is called after the promise settled or you could put doSmthElse into the .then block.
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.).
await returns [Function] instead of value
Trying to return the values of a query from firebase by making use of the async and await function. Results returned are either [Function] or Unhandled Promise Rejection Warnings. New to promises, async and await but I've tried the basic examples on a few websites, most having the resolve and reject parameters, which I assume should be the same as the firebase promises.
I tried 2 different version, both with incorrect results.
get_all_users:async function(){
ref = db.ref("/user_data");
const value = await ref.orderByKey().on("child_added", function(data){});
console.log(value.val().name);
}
returns UnhandledPromiseRejectionWarning
function get_async_users(){
ref = db.ref("/user_data");
ref.orderByKey().on("child_added", function(data) {
return data.val().name;
});
}
returns undefined
Expected either one to return the names from the query.
on is for listening to all events that ever get triggered. Therefore it does not return a Promise, as a Promise represents a single value being available, and as it does not return a Promise, you can't await it (or at least: it doesn't make sense to do so, its a no-op).
If you want to wait for the first occurence, there is once, which also returns a promise that can be awaited.
Concerning the UnhandledPromiseRejection: You should always wrap your asynchronous code into a try / catch (inside an async function), or attach a .catch to the upmost promise in the chain, then you can handle those errors correctly.
I'm running into a few different problems when trying to move nested Promise.all's into await/async.
I think I'm just not getting how I should be using Promise.all and await.
I want to do something like below - loop through an array, perform an action on it, and the results being saved to a varibale - ready to be used on the next Promise.all.
doThing() and doAThing() are both async functions.
const foo = await Promise.all(arr.map(p => doAThing(p)));
const bar = await Promise.all(foo.map(p => doAnotherThing(p)));
I'm getting lots of undefined, and it's definitely not waiting for the results to fill before continuing.
I'm really just trying to avoid nested promise alls.
Thanks,
Ollie
If doAThing() returns a promise that resolves to a value when all the asynchronous operations in it are done, then foo will be an array of those resolved values.
If you get undefined values in the foo array, then you either aren't returning anything from doAThing() or you're returning a promise that resolves to undefined.
If the await isn't waiting for all the async operations to complete, then you either aren't returning a promise at all from doAThing() or that promise is getting resolved before all the async operations are done. For all this to work properly, doAThing() has to return a promise that is ONLY resolved when all the async operations you wanted to wait for are actually done. Promises provide no magic. They have to be wired up properly to resolve when their corresponding asynchronous operations are done. If you have multiple async operations in doAThing(), then those have to be all monitored together so the function returns a single promise when they are all done (either chained or using Promise.all() themselves).
For us to help you more specifically, you'd have to show us the code for doAThing(). Then, we could show you exactly where your code needs fixing.