如何使用异步替代Promise.resolve().then()?

4
运行代码段并查看它们的持续时间,您会发现第一个代码段在执行billion loops done之前执行log('Synchronous 2')。它花费了0毫秒,但是第二个使用async关键字的代码段将阻止log('Synchronous 2')直到循环完成。

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

log('同步2') 被阻止了

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


你的问题并不清楚。你期望的结果是什么,为什么? - Pointy
你想要实现什么样的行为?你的日志调用是同步的,因此会在 Promise 解析之前发生。你想要等到 notBlocked 执行完毕后再继续吗? - Slava Knyazev
运行上面的代码,你会看到在notBlocked函数返回结果之前,log 2会运行两次。但是我想使用async await方式来编写notBlocked(),但我无法做到。 - user2734550
1
@HereticMonkey 我想弄清楚async await的限制是什么。我应该在什么情况下使用其中之一。 - user2734550
@user2734550 当涉及到可以从在线文档中学习的一般性主题时,您应该谨慎地在SO上发布。我认为您可以改进您的问题。将“我无法弄清楚…”部分更改为关于async/await的更正式问题,解释为什么您包含的代码对您来说不好。问题应该清晰明了,并且对遇到相同问题的其他用户有用。 - Steak Overflow
@user2734550 - 你不能在没有async的情况下使用await,这是将Promise -> then配对(以简化操作)的语法糖。由于代码片段按预期运行,因此不清楚您想要实现什么:第一个log是同步的,首先运行;notBlocked是异步的,被排队;第二个log是同步的,其次运行。问题出在哪里?您需要了解事件循环的工作原理 - Oleg Valter is with Ukraine
2个回答

4

异步函数会同步运行直到遇到 await,因此如果您的目标是使用异步函数来延迟一些代码作为微任务,则需要在其中添加一个 await,即使它正在等待无用的内容。

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


我想我并没有完全理解异步等待。这对我来说是一个奇怪的解决方案,但它确实有效... - user2734550
哦,是的,绝对很奇怪。我永远不会为生产编写这样的代码。 - Nicholas Tower
似乎这是异步等待的限制。 - user2734550
现在我想起来了。这与Promise.resolve().then()没有什么不同,除了大多数开发人员不会理解这里发生了什么,对吧?所以我猜这并不是async await的限制。 - user2734550

1

要在另一个 worker 中运行该函数,我会使用 setTimeout 函数。我为此创建了实用函数 detach

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


log2仍被阻塞500毫秒。 - user2734550
1
我更新了我的回答。 - Baboo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接