admin管理员组文章数量:1336568
I read the Promise/A+ specification and it says under 2.2.4:
onFulfilled or onRejected must not be called until the execution context stack contains only platform code
But in Firefox (I tested 38.2.1 ESR and 40.0.3) the following script executes the onFulfilled method synchronously:
var p = Promise.resolve("Second");
p.then(alert);
alert("First");
(It does not seem to run using alerts here, it can also be tried here: ,output)
It works as expected in other browsers or when using the ES6Promise-Polyfill.
Did I miss something here? I always though that one of the points of the then-method is to ensure asynchronous execution.
Edit:
It works when using console.log, see answer by Benjamin Gruenbaum:
function output(sMessage) {
console.log(sMessage);
}
var p = Promise.resolve("Second");
p.then(output);
output("First");
As he points out in the ments, this also happens when using synchronous requests, which is exactly why it happens in your test scenario. I created a minimal example of what happens in our Tests:
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", ".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);
}
I read the Promise/A+ specification and it says under 2.2.4:
onFulfilled or onRejected must not be called until the execution context stack contains only platform code
But in Firefox (I tested 38.2.1 ESR and 40.0.3) the following script executes the onFulfilled method synchronously:
var p = Promise.resolve("Second");
p.then(alert);
alert("First");
(It does not seem to run using alerts here, it can also be tried here: http://jsbin./yovemaweye/1/edit?js,output)
It works as expected in other browsers or when using the ES6Promise-Polyfill.
Did I miss something here? I always though that one of the points of the then-method is to ensure asynchronous execution.
Edit:
It works when using console.log, see answer by Benjamin Gruenbaum:
function output(sMessage) {
console.log(sMessage);
}
var p = Promise.resolve("Second");
p.then(output);
output("First");
As he points out in the ments, this also happens when using synchronous requests, which is exactly why it happens in your test scenario. I created a minimal example of what happens in our Tests:
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./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);
}
In Firefox this leads to:
Share Improve this question edited Sep 8, 2015 at 7:34 sirion asked Sep 7, 2015 at 13:58 sirionsirion 1,0216 silver badges13 bronze badges 6-
Returning
"Second"
,"First"
,"Third"
at firefox ? – guest271314 Commented Sep 7, 2015 at 14:10 - Exactly, it should be "First", "Second", "Third" as in Chrome - or am I missing something? – sirion Commented Sep 7, 2015 at 14:15
- 2 Want to share with you this article: jakearchibald./2015/tasks-microtasks-queues-and-schedules – Andrey Commented Sep 7, 2015 at 14:16
- 1 You can ignore the setTimeout - I don't care if that is second or third (maybe I should have left it out) - I am just concerned with "First" and "Second" being in the wrong order. – sirion Commented Sep 7, 2015 at 14:18
- Please paste the code that demonstrates the issue into your question so this question stays relevant when outside links have long since been changed or died. – jfriend00 Commented Sep 8, 2015 at 4:07
1 Answer
Reset to default 10This is because you're using alert
When you use alert
here it blocks and all bets are off - the page has frozen, execution halted and things are at "platform level".
It might be considered a bug, and it's certainly not what I would expect - but at the core this is about the inpatibility between alert
and JavaScript task/microtask semantics.
If you change that alert to a console.log
or appending to document.innerHTML
you'd get the result you expect.
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");
From what I can tell, this is actually permitted optional behavior:
Optionally, pause while waiting for the user to acknowledge the message.
(Emphasis mine)
Basically, what firefox does is this:
- Execute until it encounters the first
alert
. - Run any microtasks to pletion before pausing (tasks are paused, and not microtasks).
- The
then
is run as a microtask, so "Second" gets queued and precedes thealert
. - The
Second
alert gets run. - The
First
alert gets run.
Confusing, but allowed from what I can tell.
本文标签: javascriptFirefox Promisethen not called asynchronouslyStack Overflow
版权声明:本文标题:javascript - Firefox: Promise.then not called asynchronously - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742392319a2466231.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论