如何计算JavaScript中异步函数的执行时间?(How to calculate the execution time of an async function in JavaScript?)

我想计算一下异步函数( async / await )在JavaScript中的使用时间。

人们可以这样做:

const asyncFunc = async function () {}; const before = Date.now(); asyncFunc().then(() => { const after = Date.now(); console.log(after - before); });

但是,这不起作用,因为promises回调是在一个新的微任务中运行的。 即,在asyncFunc()的结束和then(() => {})的开头之间,将首先触发任何已经排队的微任务,并且将考虑它们的执行时间。

例如:

const asyncFunc = async function () {}; const slowSyncFunc = function () { for (let i = 1; i < 10 ** 9; i++) {} }; process.nextTick(slowSyncFunc); const before = Date.now(); asyncFunc().then(() => { const after = Date.now(); console.log(after - before); });

这会在我的机器上打印1739 ,即差不多2秒,因为它等待slowSyncFunc()完成,这是错误的。

请注意,我不想修改asyncFunc的主体,因为我需要检测许多异步函数,而无需修改每个异步函数。 否则我只能在Date.now()的开头和结尾添加一个Date.now()语句。

另请注意,问题不在于如何检索性能计数器。 使用Date.now() , console.time() , process.hrtime() (仅限Node.js)或performance (仅限浏览器)不会更改此问题的基础。 问题在于,承诺回调是在新的微任务中运行的。 如果将setTimeout或process.nextTick等语句添加到原始示例中,则表示您正在修改该问题。

I would like to calculate how long an async function (async/await) is taking in JavaScript.

One could do:

const asyncFunc = async function () {}; const before = Date.now(); asyncFunc().then(() => { const after = Date.now(); console.log(after - before); });

However, this does not work, because promises callbacks are run in a new microtask. I.e. between the end of asyncFunc() and the beginning of then(() => {}), any already queued microtask will be fired first, and their execution time will be taken into account.

E.g.:

const asyncFunc = async function () {}; const slowSyncFunc = function () { for (let i = 1; i < 10 ** 9; i++) {} }; process.nextTick(slowSyncFunc); const before = Date.now(); asyncFunc().then(() => { const after = Date.now(); console.log(after - before); });

This prints 1739 on my machine, i.e. almost 2 seconds, because it waits for slowSyncFunc() to complete, which is wrong.

Note that I do not want to modify the body of asyncFunc, as I need to instrument many async functions without the burden of modifying each of them. Otherwise I could just add a Date.now() statement at the beginning and the end of asyncFunc.

Note also that the problem is not about how the performance counter is being retrieved. Using Date.now(), console.time(), process.hrtime() (Node.js only) or performance (browser only) will not change the base of this problem. The problem is about the fact that promise callbacks are run in a new microtask. If you add statements like setTimeout or process.nextTick to the original example, you are modifying the problem.

最满意答案

任何已经排队的微任务都将首先被解雇,并且它们的执行时间将被考虑在内。

是的,没有办法解决这个问题。 如果您不希望其他任务有助于您的测量,请不要排队。 这是唯一的解决方案。

这不是promises(或async function )或具体的微任务队列的问题,它是在任务队列上运行回调的所有异步事件共享的问题。

Any already queued microtask will be fired first, and their execution time will be taken into account.

Yes, and there's no way around that. If you don't want to have other tasks contribute to your measurement, don't queue any. That's the only solution.

This is not a problem of promises (or async functions) or of the microtask queue specifically, it's a problem shared by all asynchronous things which run callbacks on a task queue.

更多推荐