如何衡量承诺的执行时间?

Viv*_*not 9 javascript typescript es6-promise

我正在尝试编写一个测量另一个函数执行时间的函数:

export class Profiler {
    public measureSyncFunc(fn: () => any): Promise<number> {
        return new Promise<number>((resolve, reject) => {
            let elapsed = 0;

            let intervalId = window.setInterval(() => {
                elapsed += 1; // this is never called
            }, 1);

            this.execFunc(fn)
                .then((result: any) => {
                    window.clearInterval(intervalId);
                    resolve(elapsed);
                });
        });
    }

    private execFunc(fn: () => any): Promise<any> {
        return new Promise<any>((resolve, reject) => {
            resolve(fn());
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我就这样使用它:

let array = generateRandomArray(100000);

instance.measureSyncFunc(bubbleSort(array))
    .then((elapsed: number) => {
        console.log(`end session: ${elapsed} seconds`);
        resolve();
    });
Run Code Online (Sandbox Code Playgroud)

bubbleSort函数是同步的,需要几秒钟才能完成.看这里的代码:

控制台中的结果是"结束会话:0秒",因为从不调用间隔回调.

你知道我怎么称呼它吗?非常感谢你们 !

tos*_*skv 7

如果您要衡量的功能始终是同步的,则实际上不需要涉及承诺。

由于要测试的函数带有参数,因此最好将其包装在箭头函数中,以便能够在其他上下文中调用它,而不必自己管理它的参数。

像这样简单的事情就可以了。

function measure(fn: () => void): number {
    let start = performance.now();
    fn();
    return performance.now() - start;
}

function longRunningFunction(n: number) {
    for (let i = 0; i < n; i++) {
        console.log(i);
    }
}

let duration = measure(() => {
    longRunningFunction(100);
});

console.log(`took ${duration} ms`);
Run Code Online (Sandbox Code Playgroud)

如果您想测量花费一个异步函数(如果它返回一个promise)来解决的时间,则可以轻松地将代码更改为如下所示:

function measurePromise(fn: () => Promise<any>): Promise<number> {
    let onPromiseDone = () => performance.now() - start;

    let start = performance.now();
    return fn().then(onPromiseDone, onPromiseDone);
}

function longPromise(delay: number) {
    return new Promise<string>((resolve) => {
        setTimeout(() => {
            resolve('Done');
        }, delay);
    });
}

measurePromise(() => longPromise(300))
    .then((duration) => {
        console.log(`promise took ${duration} ms`);
    });
Run Code Online (Sandbox Code Playgroud)

注意:此解决方案使用ES6 Promise,如果您使用其他东西,则可能需要对其进行调整,但逻辑应相同。

您可以在此处看到两个示例在操场上工作。

  • 应该注意的是,当并行运行多个 Promise 时,这种方法[不可靠](https://jsfiddle.net/mindplay/sq81op7k/) - 如果 Promise 做了任何数量的阻塞工作,结果将或多或少随机的。我已经尝试了该线程中的所有方法(截至 22 年 4 月 13 日),但没有一个起作用。我认为没有任何可靠的方法可以兑现承诺。如果您并行运行 x 个 Promise,那么您最终测量的结果取决于内部调度,并且您实际上最终测量的是所有 Promise 中最慢的 Promise 所花费的时间。 (2认同)

Ber*_*rgi 5

不要用setInterval毫秒为单位(它不准确,滞后,漂移,最小间隔约为4ms)。只需在执行前后获得两个时间戳即可。

function measureASyncFunc(fn: () => Promise<any>): Promise<number> {
    const start = Date.now();
    return fn.catch(() => {}).then(() => {
        const end = Date.now();
        const elapsed = end-start;
        return elapsed;
    });
}
Run Code Online (Sandbox Code Playgroud)

为了获得更高的精度,请替换Date.now为performance.now。