How to measure the lead time?

I am trying to write a function that measures the execution time of another function:

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

      

Then I use it like this:

let array = generateRandomArray(100000);

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

      

The bubbleSort function is synchronous and takes a few seconds to complete. See the code here :

The result in the console is "ending session: 0 seconds" because the interval callback is never called.

Do you know how I can call? Thanks a lot guys!

+3


source to share


3 answers


If the functions you want to measure will always be synchronous, there is really no need to include promises.

Since the function you want to test takes parameters, your best bet is to wrap it in an arrow function so you can call it a different context and don't need to manipulate the parameters yourself.

Something as simple as this will be fine.

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

      



If you want to measure the time it takes for an async function (if it returns a promise), you can easily change your code to something like this:

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

      

Note. This solution uses Promise ES6 in case you are using something else that you might need to adapt, but the logic should be the same.

You can see both examples working in the playground here .

+3


source


Do not use setInterval

milliseconds to count ( imprecise , lags , drifts, and has a minimum interval of about 4ms ). Just get two timestamps before and after execution.

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

      



For greater accuracy, replace Date.now

with performance.now

.

+3


source


Have a look at timeFnPromise and the corresponding test cases .

  • the target function completes and is executed when the wrapped function is called
  • adds a fulfill / reject handler to the underlying promise that returns the return values ​​of the target functions as "ret" and the elapsed time as "elapsedTime"
  • maintains arguments by passing them to the target function

Using samples:

const wrappedFn = timeFnPromise(aFunctionThatReturnsAPromise)

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

      

Also available through the NPM jschest module .

+1


source







All Articles