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

33qvvth1  于 2022-12-14  发布在  TypeScript
关注(0)|答案(5)|浏览(146)

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

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());
        });
    }
}

然后我这样使用它:

let array = generateRandomArray(100000);

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

bubbleSort函数是同步的,需要几秒钟才能完成。请参阅代码here
控制台中的结果是“结束会话:0秒”,因为从未调用间隔回调。
你知道我怎么叫它吗?非常感谢你们!

z9smfwbn

z9smfwbn1#

如果你想要测量的函数总是同步的,那么就真的没有必要涉及承诺。
由于您要测试的函数需要参数,因此最好将其 Package 在一个箭头函数中,以便能够使用另一个上下文调用它,而不必自己管理它的参数。
像这样简单的东西就可以了。

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`);

如果你想测量一个异步函数(如果它返回一个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`);
    });

注:此解决方案使用ES6 Promise,如果您使用其他解决方案,则可能需要对其进行调整,但逻辑应该相同。
你可以看到两个例子都在这里的操场上工作。

ybzsozfc

ybzsozfc2#

不要使用setInterval来计算毫秒数(它是inaccuratelagsdrifts,最小间隔大约为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;
    });
}

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

8nuwlpux

8nuwlpux3#

看一下timeFnPromise和相关的test cases

  • 在调用 Package 的函数时,将 Package 并执行目标函数
  • 将实现/拒绝处理程序附加到基础Promise,该Promise返回目标函数的返回值“ret”和经过时间“elapsedTime”
  • 通过将参数传递给目标函数来支持参数
    示例用法:
const wrappedFn = timeFnPromise(aFunctionThatReturnsAPromise)

wrappedFn()
.then((values)=>{
  const {ret, elapsedTime} = values
  console.log(`ret:[${ret}] elapsedTime:[${elapsedTime}]`)
})

也可通过NPM模块jschest获得。

vjrehmav

vjrehmav4#

这是我写的一个简单的 Package 函数。它返回一个Promise(通过async关键字),所以你可以用你的Promise调用它。我把时间值作为一个属性添加到响应中。如果你不能在响应中有这个值,那么你需要在以后删除它。

const stopwatchWrapper = async (promise) => {
  const startTime = Date.now()
  const resp = await promise
  resp.executionTime = Date.now() - startTime
  return resp
}

const axiosPromise = stopwatchWrapper(axios(reqSelected))
const response = await axiosPromise
console.log(response.executionTime)
rslzwgfq

rslzwgfq5#

toskv提出的方法只适用于单个promise的解析,如果我们想使用Promise.all(),它返回的时间结果是错误的。
下面是一个由toskv开发的代码示例,但是使用Promise.all()
承诺衡量.all()
如果有人需要测量执行Promise.all()中的每个承诺所花费的时间,可以采用的方法是使用拦截器并在那里进行时间测量

相关问题