How to use async alternative for Promise.resolve().then()?

Viewed 851

Run the snippets and look at their durations you'll see that first snippet executes log('Synchronous 2') before billion loops done. It spent 0ms, but 2nd snippet using async keyword blocks log('Synchronous 2')until the loop is finished.

const tick = Date.now();
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}ms`);

const notBlocked = () => {
    return Promise.resolve().then(() =>  {
        let i = 0;
        while(i < 1000000000) { i++; } //runs asynchronically
        return ' billion loops done';
    })
}

log(' Synchronous 1');
notBlocked().then(log);
log(' Synchronous 2');

The log('Synchronous 2') is blocked

const tick = Date.now();
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}ms`);

const notBlocked = async() => {
    let i = 0;
    while(i < 100000000) { i++; } //runs synchronically and blocks main thread
    return ' billion loops done';
}

log(' Synchronous 1');
notBlocked().then(log);
log(' Synchronous 2');

2 Answers

Async functions run synchronously until they hit an await, so if your goal is to use an async function to delay some code as a microtask, you'll need to stick an await in there, even if it's awaiting something useless.

const tick = Date.now();
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}ms`);

const notBlocked = async () => {
  await undefined; // yield until the microtasks run
  let i = 0;
  while(i < 1000000000) { i++; }
  return ' billion loops done';
}

log(' Synchronous 1');
notBlocked().then(log);
log(' Synchronous 2');

To run the function in another worker I would use the setTimeout function. I created the util function detach for this purpose:

const tick = Date.now();
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}ms`);

// Run a function in another worker.
const detach = (fn) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            fn();
            resolve();
        }, 0);
    });
}

const runLoop = () => {
    let i = 0;
    while(i < 1000000000) { i++; }
    return ' billion loops done';
}

const notBlocked = async () => {
    await detach(runLoop);
}

// Enable the use of async/await (assuming your in a module and not in an async function)
(async () => {
    log(' Synchronous 1');
    const promiseNotBlocking = notBlocked(); // Get the promise
    log(' Synchronous 2');
    await promiseNotBlocking;
})()

Related