90%的JavaScript开发者对于异步性有一个误解。(我自己也是在去年才明白的 😅)
看一下下面的简单代码:
console.log("在异步函数之前");
loopMillionTimes().then(() => console.log("返回的Promise"));
console.log("在异步函数之后");
async function loopMillionTimes() {
for (let i = 0; i <= 1000_000; i++) {
// 一些简单的操作
}
console.log("循环完成");
}
loopMillionTimes
函数是一个异步函数,因此它返回一个Promise。
那么你期望运行上面的代码会输出什么呢? 。 。 。 你可能最初期望的是: “ 在异步函数之前 在异步函数之后 循环完成 返回的Promise ”
但是如果你实际运行它,你会惊讶地发现它是: ” 在异步函数之前 循环完成 在异步函数之后 返回的Promise “
“为什么呢? loopMillionTimes
返回一个Promise,所以它不应该阻塞主线程!”
嗯……
那是因为要使代码异步,它必须使用异步API。 返回一个Promise并不能神奇地将同步代码变成异步代码。 它也不能神奇地使JavaScript多线程。
JavaScript是单线程的。因此,为了同时执行两个任务,它要求某个外部API执行某些操作,而在等待结果的同时,它继续执行并使用其主线程执行其他操作。
外部API的例子是什么呢?
- setTimeout和setInterval。
- fetch。
- Web Storage
- Web Sockets
- 读取磁盘上的文件。
这些功能从未是JavaScript语言核心的一部分,它们由某个外部运行时(如浏览器)提供,并由浏览器处理。
JavaScript只是调用此API的命令并获取结果。
因此,在我们上面的示例中,即使函数是异步的并返回一个Promise,它并未使用任何外部API,所有的代码都需要由JavaScript主线程运行,因此它是阻塞的。🤯
“好的,但是我们如何能够执行同步的长时间任务,比如计算一个大素数或循环一百万次,而不会阻塞主线程一分钟呢?”
这是我将在不久的将来的另一篇文章中讨论的,敬请关注。
如果你觉得这篇内容有用,请留下一个👍。
下次见,👋