Ответ 1
Это делается специально. Это необходимо для того, чтобы он был согласован независимо от того, известно ли значение или нет. Таким образом, существует только один порядок оценки, и вы можете зависеть от того, что независимо от того, уже обещано или нет обещание, этот порядок будет таким же.
Кроме того, делая это в противном случае, можно было бы написать код для проверки, если обещание улажено или нет, и по дизайну оно не должно быть известно и действовало.
Это довольно похоже на код обратного вызова:
function fun(args, callback) {
if (!args) {
process.nextTick(callback, 'error');
}
// ...
}
чтобы любой, кто его называет:
fun(x, function (err) {
// A
});
// B
может быть уверен, что A никогда не будет работать до B.
Спектр
См. Promises/A + Спецификация, then
Способ, пункт 4:
onFulfilled
илиonRejected
не нужно вызывать, пока стек контекста выполнения не содержит только код платформы.
См. также примечание 1:
Здесь "код платформы" означает код реализации, среды и обещания. На практике это требование гарантирует, что onFulfilled и onRejected выполняются асинхронно, после того, как цикл цикла обработки событий, который затем вызывается, и со свежим стекем. Это может быть реализовано либо с помощью механизма макрозадачи, такого как setTimeout или setImmediate, либо с помощью механизма "микрозадачи", такого как MutationObserver или process.nextTick. Поскольку реализация обещаний считается кодом платформы, она может сама содержать очередь планирования задач или "батут", в котором вызываются обработчики.
Итак, это действительно задано спецификацией.
Было подробно обсуждено, чтобы убедиться, что это требование ясное - см.: