promise.then 是否异步?

Is promise.then asynchronous or not?

以下代码在 Firefox 和 Chrome 上挂起,但在 Edge 上不挂起:

let sequence = Promise.resolve();
function fire() {
  sequence.then(fire)
};
fire();

我认为它在几个版本前的 Firefox 上没有挂起,我很困惑。这里的正确行为是什么?

编辑: Edge 37.14316 现在也挂起。

是的,Promise.then 是异步的,但是当你立即 resolve the promise,然后在回调中继续调用相同的函数时,你会陷入无限循环,浏览器会挂起

简单来说,你正在做

function fire() {
   fire(); // goes on forever
}
fire();

唯一的区别是 fire 是在已经解析并立即触发的异步回调中。

如果 Edge 没有挂起,那只是因为它可以更好地处理递归。

正确的行为是挂起1。你不会得到堆栈溢出,但异步无限递归仍然是无限递归。

1:这是微任务队列中的死循环。其他有希望的工作可能会达到 运行,但其他的不会太多。

它挂起是因为 .then 链在微任务队列上执行,不像例如setTimeout 在主 JavaScript 事件队列上执行:

let sequence = Promise.resolve();
function fire() {
  setTimeout(fire); // doesn't hang
};
fire();

大多数浏览器在当前 运行-to-completion 的尾部完全清空微任务队列,并且您的代码阻止它清空,从而拖延主 JavaScript 事件队列。

浏览器并没有完全挂起,因为用户可以在一段时间后停止这个失控的脚本。这段时间浏览器的好用程度取决于浏览器是否支持多进程。例如。 Firefox Developer Edition 在这方面比 Firefox 好,因为开发版使用多个进程。