`await` Slower Than It Should Be In Chrome

Viewed 1027

While testing the performance of await, I uncovered a confounding mystery. I ran each of the following code snippets several times each in the console to filter out flukes, and took the average times of the relevant data.

(function(console){
    "use strict";
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const O_0 = O[0];
        O[0] = O_0;
    }
    console.timeEnd();
})(console);

Resulting in: default: 5.322021484375ms

Next, I tried adding making it asynchronous

(async function(console){
    "use strict";
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const O_0 = O[0];
        O[0] = O_0;
    }
    console.timeEnd();
})(console);

Nice! Chrome knows its stuff. Very low overhead: default: 8.712890625ms

Next, I tried adding await.

(async function(console){
    "use strict";
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const O_0 = O[0];
        O[0] = await O_0;
    }
    console.timeEnd();
})(console);

This results in 100x speed reduction: default: 724.706787109375ms

So, there must be some logical reason, right? I tried comparing the types prior.

(async function(console){
    "use strict";
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const O_0 = O[0];
        O[0] = typeof O_0 === "object" ? await O_0 : O_0;
    }
    console.timeEnd();
})(console);

Okay, so that is not it: default: 6.7939453125ms

So then, it must be the promise-part: checking to see if the item passed to await is a promise. That must be the culprit, am I right or am I right?

(async function(console, Promise){
    "use strict";
    const isPromise = Promise.prototype.isPrototypeOf.bind(Promise);
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const O_0 = O[0];
        O[0] = isPromise(O_0) ? await O_0 : O_0;
    }
    console.timeEnd();
})(console, Promise);

This results in: default: 7.2041015625ms

Okay, okay, let us give Chrome the benefit of the doubt. Let us assume, for a second, that they programmed await far less than perfectly.

(async function(console, Promise){
    "use strict";
    const isPromise = Promise.prototype.isPrototypeOf.bind(Promise.prototype);
    console.time();
    var O = [1];
    for (var i=0; i !== 107000; ++i) {
        const isAnObject = typeof O[0] === "object" ? true : false;
        const isThisAPromise = isPromise(O[0]);
        O[0] = isAnObject && isThisAPromise ? await O[0] : O[0];
    }
    console.timeEnd();
})(console, Promise);

But even this fails to explain the poor performance of await: default:7.85498046875ms

Okay, honestly, I give up. I would think that await would be at least 100x faster than it is now. I cannot think of a single good reason why it would not be 100x faster in a perfect world. However, we do not live in a perfect world, so there inlies the question: how? How? How is it this slow? Is there any hope of it being any faster in the future (like maybe, say, around about 100x faster)? I am looking for facts and an objective analysis of this issue that would explain the puzzling mystery I am seeing in the above performance tests.

1 Answers

You can easily observe a difference between an await expression and lack thereof. At the very least, you are asking the engine to look at the microtask queue, possibly doing other work that happened as a result of I/O completing. Given that, this cannot possibly be optimized into nothing.

If you truly wish to spin the CPU for a few milliseconds, don't write await.

Here's an example. It prints 1 2 3.

Promise.resolve().then(()=>console.log(2));

(async()=>{
  console.log(1);
  await undefined;
  console.log(3);
})();

await undefined is not a "do-nothing" statement. It's JavaScript's cooperative multitasking.

Related