javascript - 是否需要setTimeout?

标签 javascript asynchronous async-await settimeout

我有一个关于 async、await 和 setTimeout() 的问题。 我想,我使用异步函数来处理缓慢的进程。所以我尝试了一个大循环。在我的计算机上,运行以下代码需要几秒钟:

function slowFunction() {
    return new Promise(resolve => {
        setTimeout(() => {
            for (let i = 0; i < 4000000000; i++) {};
            resolve('Ready at ' + new Date().toLocaleTimeString('de'));
        }, 0);
    });
};


console.log('Start: ' + new Date().toLocaleTimeString('de'));

(async () => {
    console.log('Call slow function.');
    console.log(await slowFunction());
})();

console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

输出为:

Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:20
Ready at 16:39:23

现在的问题是:与下一个代码有什么不同:

function slowFunction() {
    return new Promise(resolve => {
        for (let i = 0; i < 4000000000; i++) {};
        resolve('Ready at ' + new Date().toLocaleTimeString('de'));
    });
};

console.log('Start: ' + new Date().toLocaleTimeString('de'));

(async () => {
    console.log('Call slow function.');
    console.log(await slowFunction());
})();

console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

输出为:

Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:23
Ready at 16:39:23

通过第一个示例,它看起来像异步。在第二个示例中,函数等待循环结束。

我是否必须使用 setTimeout 或者我的代码有错误或者我弄错了?在这两种情况下,解析语句都位于大循环后面。

大多数 async 和 await 的例子都使用 setTimeout,但我认为,这只是为了模拟中断。

感谢您提前提供的帮助。

最诚挚的问候 帕斯卡

最佳答案

TL:DR

Promise 和 async 函数不会将您的代码卸载到另一个线程。如果您想将长时间运行的进程移出主线程,请在浏览器上查看 web workers ,在 Node.js 上查看 child processes .

详细信息

Promises 和 async 函数(只是创建和使用 Promise 的语法)不会将您的处理移动到任何其他线程,它仍然发生在您启动进程的同一线程上。他们所做的唯一事情是确保异步调用thencatch回调。它们不会使您的代码异步(除了确保回调异步发生之外)。

因此,使用 setTimeout 的第一个 block 只是设置超时,返回 promise ,然后当超时到期时,它会在运行缓慢的进程执行时阻塞主线程。这只是当阻塞发生一点点时改变,它不会改变阻塞的事实。

您可以在这里看到这种效果,注意当长时间运行的进程发生时计数器如何暂停:

function slowFunction() {
  return new Promise(resolve => {
    setTimeout(() => {
      const stop = Date.now() + 2000;
      while (Date.now() < stop) {
        // busy wait (obviously, never really do this)
      }
    }, 1000);
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000);
.as-console-wrapper {
  max-height: 100% !important;
}

不使用 setTimeout 的第二个 block 会立即阻塞,因为 Promise 执行器函数(您传递给 new Promise 的函数)会立即同步运行,并且您没有做任何事情来使其异步。

你可以在这里看到;计数器立即暂停,而不是稍后:

function slowFunction() {
  return new Promise(resolve => {
    const stop = Date.now() + 2000;
    while (Date.now() < stop) {
      // busy wait (obviously, never really do this)
    }
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000);
.as-console-wrapper {
  max-height: 100% !important;
}

直到长时间运行的代码完成之后,我们才看到 before SlowFunction 日志出现,因为浏览器永远没有机会重新绘制,我们的线程被占用了。

关于async函数:async函数中的代码开始是同步的,并且在第一个await之前都是同步的code> (或其他构造,例如 setTimeout,安排稍后执行的事情)。只有后面的代码是异步的(因为它必须等待)。

下面是一个示例,说明了这一点:

async function foo() {
  console.log("before await");
  await Promise.resolve();
  console.log("after await");
}

console.log("before foo");
foo()
  .then(() => {
    console.log("then handler on foo's promise");
  })
  .catch(console.error);
console.log("after foo");

这是它的输出:

before foo
before await
after foo
after await
then handler on foo's promise

注意before wait如何出现在after foo之前;它与对 foo 的调用同步。但是 after wait 直到稍后才会发生(因为 await Promise.resolve() 必须使其后面的代码异步发生;它是 then 的语法糖,它 promise 不会同步调用其处理程序,即使 promise 已经解决)。

关于javascript - 是否需要setTimeout?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50532391/

相关文章:

javascript - ajax响应创建laravel删除按钮

javascript - 检测背景选项卡是否在 javascript 或 jQuery 中打开

c# - C# 中的 Async Func - 正确的 async await 用法

javascript - 使用 r.js 构建整个项目,而不需要 require.js 的开销

javascript - 如何在页面加载后使用 JS 执行繁重的 PHP 函数以加快速度?

winforms - 如何异步使用SaveFileDialog?

javascript - 同步处理嵌套数组

c# - await 关键字可以生成并行代码吗?

c# - Azure 表存储的 ExecuteAsync() 无法插入所有记录

javascript - 在 javascript 中应用参数不起作用