Open utterances-bot opened 3 years ago
Good to see such nitty-gritty details about promises, thx for explanation
Good to see such nitty-gritty details about promises, thx for explanation
You're welcome @aymkin!
I was actually going to demo this exact topic to my work mates. Only difference, was I would have done the try/catch in the run function.. just because that is how we roll.
Cool! Thanks for clarifying these behaviors.
awesome
Thanks a lot!
I think this is drawing the wrong conclusion. The problem is that try/catch belongs in the run function , not in the divideWithoutAwait function. If you put it there then it will catch the rejected promise and output the desired error message.
If I would like to handle error in that return, I would do return promise.catch(err=>{}) rather than try catch block with await on return. It feels a little smelly for me to return await.
There is a lot to think about here. Error handling is definitely important. But the difference between return await promise
and return promise
isn't directly related to wrapping a try/catch around them. Think of a related implementation where your function returned a closure that did the operation. You would have the same conversation. Of course the exception is generated when you execute the closure! Here the expectation should be that you need to deal with the exception where you wait on it. More interesting is how this impacts concurrency (the aspect of using async/await that isn't demo'd computing something). Are there patterns where waiting to block on the final value later (possible pulling together multiple promises)? If I have a tree of promises and I block sub-trees early then I have the potential of building a dependency on a longer operation before I need it. Also interesting is if return promise
is faster than return await promise
. The second should have to wait for the promise and then wrap that return value in a new promise to return from the async function for the function that actually wants to value to await on. I suspect this is all heavily optimized in the javascript engines so maybe it isn't a big deal but it is still wasted cycles.
One tricky use case I've stumbled upon, when you are throwing result of the promise:
async function getData() {
const result = await fetch(url); // Promise<{someData: any}> | Promise<{ error: string }>
if (result.status >= 400) {
throw await result.json();
}
return result.json();
}
you want json to be resolved before thowing as an error.
I think this is drawing the wrong conclusion. The problem is that try/catch belongs in the run function , not in the divideWithoutAwait function. If you put it there then it will catch the rejected promise and output the desired error message.
@mvolkmann Nope, the conclusion is right. Only if you want to catch the rejection of a promise you're returning, then use return await promise
.
If I would like to handle error in that return, I would do return promise.catch(err=>{}) rather than try catch block with await on return. It feels a little smelly for me to return await.
@konriz That's a personal taste rather than a code smell. Plus, these aren't examples that argue any kind of best practice.
It is definitely code smell, although I agree that at this stage could be too early to say that.
I you see the divideWithAwait/divideWithoutAwait
functions as part of an API and run()
as the consumer of the API, catching an error and logging while returning undefined
is way worse than let the error bubble up.
If you consume a promise-based API is totally legit to expect errors, that's one of the nice things about Promises that async/await
is destroying for the junior devs.
@pietro909
It is definitely code smell, although I agree that at this stage could be too early to say that.
I think the first part of the sentence contradicts the second part of the sentence.
I you see the divideWithAwait/divideWithoutAwait functions as part of an API and run() as the consumer of the API, catching an error and logging while returning undefined is way worse than let the error bubble up.
These are just simple examples to demonstrate the difference between return promise
and return await promise
. These aren't examples that argue any kind of best practice.
If you consume a promise-based API is totally legit to expect errors, that's one of the nice things about Promises that async/await is destroying for the junior devs.
It depends on how you design the API. It is legit, for my example, to catch the error and return NaN
:
async function divideWithAwait() {
try {
return await promisedDivision(5, 0);
} catch (error) {
return NaN;
}
}
"At this step, you have seen that using return await promise and return promise don’t differ. At least when dealing with successfully fulfilled promises."
I don't believe this is quite true. return await promise
explicitly returns the result of the promise which was await
ed. If I have a Promise that just returns a value (i.e. const myPromise = async () => Promise.resolve(3)
) then return await myPromise
returns the value 3
itself. If I return myPromise
that returns a Promise
which resolves to 3
which needs to be handled very differently in the calling code.
I think these appeared to be the same in the code you presented above since there was an await
on the return of divideWithAwait
in the run
function. So in the case we returned a Promise
we from divideWithAwait
we were await
ing the Promise
in run
which gave us 6 / 2 = 3
. And in the case we await
ed the Promise
in divideWithAwait
we returned 3
which we then await
ed again in run
which is just a no-op.
I think these appeared to be the same in the code you presented above since there was an await on the return of divideWithAwait
@jbean96 That's the idea: the behavior is the same if the function invocation result is awaited.
@jbean96 You would be right if we wouldn't be inside async functions (which we need to enable the await keyword).
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
async function returnsPromise() {
return 3; // returns Promise.resolve(3);
}
async function returnsPromiseAsWell() {
return await Promise.resolve(3); // returns Promise.resolve(3);
}
'return await promise' vs 'return promise' in JavaScript
Is there any difference between using 'return await promise' and 'return promise' in asynchronous JavaScript functions?
https://dmitripavlutin.com/return-await-promise-javascript/