gpt4 book ai didi

javascript - Firefox:Promise.then 不被异步调用

转载 作者:可可西里 更新时间:2023-11-01 02:40:15 27 4
gpt4 key购买 nike

我阅读了 Promise/A+ 规范,它在 2.2.4 下说:

onFulfilled or onRejected must not be called until the execution context stack contains only platform code

但是在 Firefox 中(我测试了 38.2.1 ESR 和 40.0.3)下面的脚本同步执行了 onFulfilled 方法:

var p = Promise.resolve("Second");
p.then(alert);
alert("First");

(这里好像没有使用alerts运行,这里也可以试试:http://jsbin.com/yovemaweye/1/edit?js,output)

它在其他浏览器中或在使用 ES6Promise-Polyfill 时按预期工作。

我在这里错过了什么吗?我一直认为 then 方法的要点之一是确保异步执行。

编辑:

它在使用 console.log 时有效,请参阅 Benjamin Gruenbaum 的回答:

function output(sMessage) {
console.log(sMessage);
}

var p = Promise.resolve("Second");
p.then(output);

output("First");

正如他在评论中指出的那样,在使用同步请求时也会发生这种情况,这正是它在您的测试场景中发生的原因。我创建了一个最小示例来说明我们的测试中发生的情况:

function request(bAsync) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
resolve(xhr.responseText);
}
});
xhr.open("GET", "https://sapui5.hana.ondemand.com/sdk/resources/sap-ui-core.js", !!bAsync);
xhr.send();
});
}

function output(sMessage, bError) {
var oMessage = document.createElement("div");
if (bError) {
oMessage.style.color = "red";
}
oMessage.appendChild(document.createTextNode(sMessage));
document.body.appendChild(oMessage);
}

var sSyncData = null;
var sAsyncData = null;

request(true).then(function(sData) {
sAsyncData = sData;
output("Async data received");
});

request(false).then(function(sData) {
sSyncData = sData;
output("Sync data received");
});


// Tests
if (sSyncData === null) {
output("Sync data as expected");
} else {
output("Unexpected sync data", true);
}
if (sAsyncData === null) {
output("Async data as expected");
} else {
output("Unexpected async data", true);
}

在 Firefox 中,这会导致:

enter image description here

最佳答案

这是因为你正在使用alert

当您在此处使用 alert 时,它会阻塞并且所有赌注都会关闭 - 页面已卡住,执行停止并且一切都处于“平台级别”。

它可能被认为是一个错误,这当然不是我所期望的 - 但核心是关于 alert 和 JavaScript 任务/微任务语义之间的不兼容性。

如果您将该警报更改为 console.log 或附加到 document.innerHTML,您将获得预期的结果。

var alert = function(arg) { // no longer a magical and blocking operation
document.body.innerHTML += "<br/>" + arg;
}

// this code outputs "First, Second, Third" in all the browsers.

setTimeout(alert.bind(null, "Third"), 0);

var p = Promise.resolve("Second");
p.then(alert);

alert("First");

据我所知,这实际上是 permitted optional behavior :

Optionally, pause while waiting for the user to acknowledge the message.

(强调我的)

基本上,firefox 所做的是这样的:

  • 执行直到遇到第一个alert
  • 在暂停之前运行任何微任务直至完成(暂停的是任务,而不是微任务)。
  • then 作为微任务运行,因此“Second”进入队列并在 alert 之前。
  • 第二个 警报运行。
  • 运行第一个 警报。

令人困惑,但据我所知是允许的。

关于javascript - Firefox:Promise.then 不被异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32440451/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com