Firefox: Promise.then не называется асинхронно

Я прочитал спецификацию Promise/A + и в разделе 2.2.4:

onFulfilled или onRejected не должны вызываться, пока стек контекста выполнения не содержит только код платформы

Но в Firefox (я тестировал 38.2.1 ESR и 40.0.3) следующий script синхронно выполняет синхронный метод onFulfilled:

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

(Кажется, он не запускается с помощью предупреждений, здесь также можно попробовать: http://jsbin.com/yovemaweye/1/edit?js,output)

Он работает так, как ожидалось, в других браузерах или при использовании ES6Promise- Polyfill.

Я что-то пропустил? Я всегда, хотя одна из точек тогда-метода заключается в обеспечении асинхронного выполнения.

Изменить:

Он работает при использовании 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);
}

Ответ 1

Это связано с тем, что вы используете 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");