- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我知道一些关于 microtask 和 Promise 的事情,比如 Promise.prototype.then
中的 handler 会在调用栈为空时被排入 microtask 并执行,它可能被用来避免竞争条件或其他有关并发的内容。
但是如果我们不引入 microtask 会怎样呢?
最佳答案
让我们来看这个示例代码:
Promise.resolve("resolved").then(i => console.log("resolved"));
console.log("start");
这是一个立即(同步)解决的 promise 。当执行 then
方法时,它已经处于已解决状态。然而,对 then
的回调不会立即执行。相反,一个作业被放入作业队列(微任务)。所以我们得到这个输出:
start
resolved
你的问题是如果没有这样的作业调度它是否可以工作,这意味着回调将立即执行以便结果将是:
resolved
start
对于示例代码,这确实是一个可行的替代方案。但现在再举一个例子,其中 promise 不是由 JavaScript 代码解决的,而是由一个较低级别的事件解决的,该事件深深地埋在一个 API 中,该 API 用一个 promise 接口(interface)封装了它。假设它是一些读取文件内容的 API:
readFile(path).then((content) => console.log("file contents: " + content));
console.log("start of a lot of work");
for (let i = 0; i < 1e7; i++) {
// some work
}
console.Log("end of a lot of work");
因此,根据 Promise 规范,这将输出:
start of a lot of work
end of a lot of work
file contents: .....
现在假设工作循环需要 3 秒才能完成,并且文件读取 API 有一个将大部分工作委托(delegate)给操作系统函数的实现。这些操作系统功能将根据操作系统处理架构运行,通常是某种形式的事件驱动多任务处理。这里的本质是,操作系统将能够在 JS 循环进行的同时进行文件操作。
我们还假设文件读取在 1 秒内完成。一个事件从操作系统冒泡到 API 的非 JavaScript 中间件,准备好冒泡到 JavaScript“世界”。现在应该怎么办?我们可以想象有两种选择:
作业被放入作业队列,这表明 promise 已解决并且需要调用 then
回调。这就是它的实际工作方式。
正在运行的 JavaScript 循环被中断,readFile
返回的 promise 得到解决,then
回调被调用片刻。回调完成后,被中断的执行上下文将恢复,并继续完成。
后一种机制可能会导致整个中断链,其中甚至 then
回调中的代码也可能被另一个 promise-resolution 事件中断,...等等。这可能导致必须像堆栈一样维护的执行上下文的构建。这会使代码执行变得不可预测、难以调试并且容易发生堆栈溢出。
在我看来,这些是此选项不可取的原因,也是我们拥有选项 1 的原因。即使第二个选项适用于纯粹使用 JavaScript 创建的 promise ——不依赖于一些较低级别的异步行为——如果这些 promise 与 API 提供的行为具有不同的行为,那将是奇怪的。当涉及到 then
回调执行和作业队列的使用时,它们都应该使用相同的行为。
关于javascript - 为什么 Javascript 规范设计者在 promise 中引入了 microtask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55016554/
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭11 年前。 Improve th
我是一名优秀的程序员,十分优秀!