我正在尝试编写一个测量另一个函数执行时间的函数:
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秒”,因为永远不会调用间隔回调。
你知道我怎么能打电话吗? 非常感谢你们!
答案 0 :(得分:5)
如果您要测量的功能始终是同步的,则实际上不需要涉及承诺。
由于您要测试的函数采用参数,因此最好将其包装在箭头函数中,以便能够使用其他上下文调用它,而不必自己管理它的参数。
像这样简单的东西就可以了。
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 ,如果您正在使用其他东西,则可能需要对其进行调整,但逻辑应该相同。
您可以在操场here中看到这两个示例。
答案 1 :(得分:4)
请勿使用setInterval
来计算毫秒数(它是inaccurate,lags,drifts,最小间隔约为4毫秒。只需在执行之前和之后获得两个时间戳。
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
。
答案 2 :(得分:1)
查看timeFnPromise和相关的test cases。
样本用法:
const wrappedFn = timeFnPromise(aFunctionThatReturnsAPromise)
wrappedFn()
.then((values)=>{
const {ret, elapsedTime} = values
console.log(`ret:[${ret}] elapsedTime:[${elapsedTime}]`)
})
也可通过NPM模块jschest获得。
答案 3 :(得分:0)
这是我编写的一个简单包装函数。它返回一个Promise(通过async关键字),因此您可以按自己的承诺来调用它。我将时间值作为属性添加到响应中。如果您无法在响应中包含该值,则需要随后将其删除。
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)
答案 4 :(得分:0)
最好澄清一下,toskv 提出的方法仅适用于解决单个承诺。如果我们要使用 Promise.all() 返回的时间结果是错误的。
这是一个使用 Promise.all() 开发的代码示例,但使用了 Promise.all()
如果有人需要测量使用 Promise.all() 执行的每个承诺所需的时间,可以遵循的方法是利用拦截器并在那里进行时间测量