I know that the async await
is the new Promise
in the town and it is a new way to write asynchronous code and I also know that
We didn’t have to write .then
, create an anonymous function to handle the response
Async/await
makes it finally possible to handle both synchronous and asynchronous errors with the same construct, good old try/catch
The error stack returned from a promise
chain gives no clue of where the error happened. However, the error stack from async/await points to the function that contains the error
AND SO ON...
but here I have done a simple bench mark
In the benchmark I have run 2 loops for 1 million times. In first loop I am calling a function that is returning 1 in another function I am calling a function that is throwing 1 as an exception.
the time taken by first loop which is calling a function that is returning 1 is almost half of the function that is throwing 1 as error.
Which shows that time taken by throw
is almost double of the time taken by return
node v7.4 linux/amd64
return takes 1.233seconds
1000000
throw takes 2.128seconds
1000000
Benchmark Code Below
function f1() {
return 1;
}
function f2() {
throw 1;
}
function parseHrtimeToSeconds(hrtime) {
var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
return seconds;
}
var sum = 0;
var start = 0;
var i = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
var seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('return takes ' + seconds + 'seconds');
console.log(sum);
sum = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('throw takes ' + seconds + 'seconds');
console.log(sum);
I know that the async await
is the new Promise
in the town and it is a new way to write asynchronous code and I also know that
We didn’t have to write .then
, create an anonymous function to handle the response
Async/await
makes it finally possible to handle both synchronous and asynchronous errors with the same construct, good old try/catch
The error stack returned from a promise
chain gives no clue of where the error happened. However, the error stack from async/await points to the function that contains the error
AND SO ON...
but here I have done a simple bench mark https://repl.it/repls/FormalAbandonedChimpanzee
In the benchmark I have run 2 loops for 1 million times. In first loop I am calling a function that is returning 1 in another function I am calling a function that is throwing 1 as an exception.
the time taken by first loop which is calling a function that is returning 1 is almost half of the function that is throwing 1 as error.
Which shows that time taken by throw
is almost double of the time taken by return
node v7.4 linux/amd64
return takes 1.233seconds
1000000
throw takes 2.128seconds
1000000
Benchmark Code Below
function f1() {
return 1;
}
function f2() {
throw 1;
}
function parseHrtimeToSeconds(hrtime) {
var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
return seconds;
}
var sum = 0;
var start = 0;
var i = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
var seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('return takes ' + seconds + 'seconds');
console.log(sum);
sum = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('throw takes ' + seconds + 'seconds');
console.log(sum);
Share
Improve this question
edited Nov 28, 2017 at 6:11
Vikas Bansal
asked Nov 28, 2017 at 5:52
Vikas BansalVikas Bansal
11.7k16 gold badges63 silver badges105 bronze badges
1
|
4 Answers
Reset to default 14Your benchmark has nothing to do with the performance between async/await
vs raw promises. All I can see is that throwing an error takes a longer time to compute. This is expected.
Back to the main question, should use async/await
rather than .then
with raw promises?
Keep in mind that async/await
is merely syntactic sugar over raw promises, so there shouldn't be much impact on the overall performance. However, it does make your code more linear which removes a lot of cognitive overhead from the developer.
The conclusion is use what you prefer. Promises can be polyfill'd but new syntaxes cannot, so you might want to keep that in mind when deciding which style to use.
Some misunderstanding:
The error stack returned from a promise chain gives no clue of where the error happened
That is not true. A quick check with:
function error() {
return new Promise(function(res, rej) {
res(undefined()); // uh oh
});
}
error().then(console.log, e => console.log("Uh oh!", e.stack));
shows the entire error stack including the location.
As most things go, the answer is "it depends".
Before talking about performance, the more important aspect is the maintainability of the code, and limitation of async
/await
vs raw Promise
.
async
/await
is a great way to execute asynchronous code sequentially, while Promise
enables you to run asynchronous code concurrently.
async function foo() {
const a = await backend.doSomething()
const b = await backend.doAnotherThing()
return a + b
}
In the code above, backend.doAnotherThing()
will not be executed until backend.doSomething()
has returned. On the other hand:
function foo() {
Promise.all([backend.doSomething(), backend.doAnotherThing()])
.then(([a, b]) => {
return a + b
})
}
will execute both calls, and wait for both to complete.
As you mentioned about the benefits of async
/await
, I personally use it extensively. Except for the cases above.
If you need performance and to you, the performance difference between async
/await
vs Promise
is more important than the readability benefit of async
/await
over Promise
, by all mean go ahead.
As long as it is a conscious choice, you should be fine.
UPDATE: as mentioned by Derek 朕會功夫
You can get parallel execution with async
/await
by:
async function foo() {
const p1 = backend.doSomething()
const p2 = backend.doAnotherThing()
return await p1 + await p2
}
Building on unional's answer:
You can achieve the same behavior as Promise.all
with async/await
function foo() {
Promise.all([backend.doSomething(), backend.doAnotherThing()])
.then(([a, b]) => {
return a + b
})
}
async function foo() {
const a = backend.doSomething()
const b = backend.doAnotherThing()
return await a + await b
}
Backend tasks happen concurrently and we wait on both to be finished before we return. See also the MDN example I wrote
Based on this I am not sure if there is any performance advantage to directly using Promises over async/await
.
I want to answer this question from the opposite direction, i.e. when to use promise over async/await. And other than these cases I think using async/await will be more appropriate.
So except for Promise concurrency I will use async/await. There are four static methods for Promise concurrency.
The others answers have mentioned Promise.all()
but if you need to all promise to be settled you can choose Promise.allSettled()
For Promise.any()
I have a use case for it, Is it possible to break away from await Promise.all when any promise has fulfilled (Chrome 80)
The difference between Promise.any()
and Promise.race()
is Promise.any()
rejects when all of the promises reject while Promise.race()
rejects when any of the promises rejects.
One use case for Promise.race()
is to implement a timeout because async/await doesn't have built-in support for timeout.
I will just copy the code from https://www.freecodecamp.org/news/how-to-use-promises-in-javascript/. All the credit to the author.
async function fetchDataWithTimeout() {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout exceeded')), 5000);
});
try {
const response = await Promise.race([fetch('https://api.example.com/data'), timeoutPromise]);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
Adding timeout function is probably the only case I still need to write new Promise((resolve, reject) => {...})
explicitly.
Before async/await I sometime made Promise constructor antipattern, i.e. manually creating a Promise over another promise (the return value of some web call). Using promise chain is one way to fix that antipattern but using async/await makes my codes more readable.
await
awaits apromise
, the premise of your question is really kind of wrong. It's reallyawait
vs..then()
, notawait
vs.promise
. When usingawait
with an async operation, there's always a promise involved because anyasync
function returns a promise so you aren't avoiding a promise when usingawait
. – jfriend00 Commented Nov 28, 2017 at 6:24