1

I have a problem with understanding how do async functions in js work. So I need to call async function for 5 times and measure the duration of every execution. In the end I should have an array with 5 time values. I have smth like this

for (let i = 0; i < 5; i++) {
    const run = async () => {
    await test(thisTest, filename, unitTestDict);
    };
    measure(run).then(report => {
                        // inspect
                        const {tSyncOnly, tSyncAsync} = report;
                        // array.push(tSyncAsync) 
                        console.log(`∑ = ${tSyncAsync}ms \t`);
                    }).catch(e => {
                        console.error(e)
                    });
}

Here I found the realization of time measure function:


class Stack {
    constructor() {
        this._array = []
    }

    push(x) {
        return this._array.push(x)
    }

    peek() {
        return this._array[this._array.length - 1]
    }

    pop() {
        return this._array.pop()
    }

    get is_not_empty() {
        return this._array.length > 0
    }
}

class Timer {
    constructor() {
        this._records = new Map
        /* of {start:number, end:number} */
    }

    starts(scope) {
        const detail =
            this._records.set(scope, {
                start: this.timestamp(),
                end: -1,
            })
    }

    ends(scope) {
        this._records.get(scope).end = this.timestamp()
    }

    timestamp() {
        return performance.now()
    }

    timediff(t0, t1) {
        return Math.abs(t0 - t1)
    }

    report(scopes, detail) {
        let tSyncOnly = 0;
        let tSyncAsync = 0;
        for (const [scope, {start, end}] of this._records)
            if (scopes.has(scope))
                if (~end) {
                    tSyncOnly += end - start;
                    tSyncAsync += end - start;
                    const {type, offset} = detail.get(scope);
                    if (type === "Timeout")
                        tSyncAsync += offset;
                }
        return {tSyncOnly, tSyncAsync}
    }
}

async function measure(asyncFn) {
    const stack = new Stack;
    const scopes = new Set;
    const timer = new Timer;
    const detail = new Map;
    const hook = createHook({
        init(scope, type, parent, resource) {
            if (type === 'TIMERWRAP') return;
            scopes.add(scope);
            detail.set(scope, {
                type: type,
                offset: type === 'Timeout' ? resource._idleTimeout : 0
            })
        },
        before(scope) {
            if (stack.is_not_empty) timer.ends(stack.peek());
            stack.push(scope);
            timer.starts(scope)
        },
        after() {
            timer.ends(stack.pop())
        }
    });
    return await new Promise(r => {
        hook.enable();
        setTimeout(() => {
            asyncFn()
                .then(() => hook.disable())
                .then(() => r(timer.report(scopes, detail)))
                .catch(console.error)
        }, 1)
    })
}

I can call it inside the loop and get console.log with time for every iteration:

measure(run).then(report => {
                        // inspect
                        const {tSyncOnly, tSyncAsync} = report;
                        // array.push(tSyncAsync) 
                        console.log(`∑ = ${tSyncAsync}ms \t`);
                    }).catch(e => {
                        console.error(e)
                    });

But when I try to push this console values to array, nothing comes out, the array remains empty. Is there a way to fill it in?

Anya
  • 13
  • 4
  • I don't understand your initial `for` loop. It defines an async function and assigns that to a variable named `run`, but never actually calls that function to execute it. – jfriend00 May 27 '20 at 20:50
  • That's a pretty complicated way to measure execution time, do you really need this? I think you're looking for [something far simpler](https://stackoverflow.com/a/44158747/1048572). – Bergi May 27 '20 at 20:51
  • I corrected my question, now the loop is fully specified – Anya May 27 '20 at 20:59
  • @Bergi ok, this function is much better, but I still don't understand how to return not promise, but numerical values that could be put into array... – Anya May 27 '20 at 21:30
  • @Anya You can't - the asynchronous task will always return a promise, you will need to wait until it's done before you can access the timing value. Just put an `await` in your loop: `results.push(await measure(run))` – Bergi May 27 '20 at 21:49
  • Take a look at [Console Timers](https://developer.mozilla.org/en-US/docs/Web/API/console#Timers). – D. Pardal May 28 '20 at 07:36

0 Answers0