Статья впервые опубликована авторомGithub.
Обещание Каждый должен иметь возможность умело использовать API, но у вас все еще могут быть пробелы в знаниях, связанные с микрозадачами.
Предварительное знание
Перед началом текста некоторые из контента мы первой статьи охватывают аванс, установите тон.
Какие API-интерфейсы Promise включают микрозадачи?
В Promise в микрозадачах участвуют только обратные вызовы, которые необходимо выполнить после изменения состояния, напримерthen
,catch
,finally
, все остальные исполнения кода являются макрозадачами (синхронное выполнение).
На приведенном выше рисунке синим цветом обозначено синхронное выполнение, а желтым — асинхронное выполнение (переброшенное в очередь микрозадач).
Когда эти микрозадачи добавляются в очередь микрозадач?
Давайте посмотрим на эту проблему в соответствии со спецификацией ecma:
-
Если в это время состояние Promise находится в состоянии ожидания, то обратный вызов успеха или неудачи будет добавлен к
[[PromiseFulfillReactions]]
а также[[PromiseRejectReactions]]
середина. Если вы посмотрите на код написанных от руки обещаний, то увидите, что есть два массива, в которых хранятся эти функции обратного вызова. -
Если в это время состояние Promise не находится в состоянии ожидания, обратный вызов станет Promise Jobs, то есть микрозадачами.
После осмысления вышеуказанных знаний начинается художественный фильм.
То же самое, разные микрозадачи выполняются
начальный
Promise.resolve()
.then(() => {
console.log("then1");
Promise.resolve().then(() => {
console.log("then1-1");
});
})
.then(() => {
console.log("then2");
});
Приведенный выше код должен иметь возможность получить правильный ответ:then1 → then1-1 → then2
.
несмотря на то чтоthen
выполняется синхронно, и состояние также изменилось. Но это не значит, что каждая встречаthen
Нам всем нужно бросить его обратный вызов в очередь микрозадачи, но подождитеthen
После выполнения обратного вызова выполняется соответствующая операция по ситуации.
Исходя из этого, можно сделать первый вывод:В цепочке вызовов только предыдущийthen
После выполнения обратного вызоваthen
будут добавлены в очередь микрозадач.
средний
все знаютPromise resolve
с последующимthen
Обратный вызов немедленно попадет в очередь микрозадач.
Как вы думаете, каким будет вывод следующего кода?
let p = Promise.resolve();
p.then(() => {
console.log("then1");
Promise.resolve().then(() => {
console.log("then1-1");
});
}).then(() => {
console.log("then1-2");
});
p.then(() => {
console.log("then2");
});
По первоначальному пониманию нам не сложно нарисоватьthen2
Будет вthen1-1
После выхода, но на самом деле ситуация обратная.
На основании этого делаем второй вывод:Начало каждого цепного вызова сначала будет по очереди входить в очередь микрозадач.
Дальше пишем иначе:
let p = Promise.resolve().then(() => {
console.log("then1");
Promise.resolve().then(() => {
console.log("then1-1");
});
}).then(() => {
console.log("then2");
});
p.then(() => {
console.log("then3");
});
Приведенный выше код на самом деле имеет ловушку,then
Каждый раз возвращается новое обещание, в это времяp
больше никогдаPromise.resolve()
создан, но последнийthen
генерируется, поэтомуthen3
должен быть вthen2
распечатал позже.
Кстати, мы также можем оптимизировать выводы, сделанные ранее, как:Начало каждого связанного вызова одного и того же промиса сначала будет по очереди входить в очередь микрозадач.
передовой
Вы можете предположить следующееthen1-2
Когда он будет напечатан?
Promise.resolve()
.then(() => {
console.log("then1");
Promise.resolve()
.then(() => {
console.log("then1-1");
return 1;
})
.then(() => {
console.log("then1-2");
});
})
.then(() => {
console.log("then2");
})
.then(() => {
console.log("then3");
})
.then(() => {
console.log("then4");
});
Этот вопрос должен быть простым, запомните первый вывод, чтобы получить ответ, следующий анализ:
-
первый раз
resolve
после первогоthen
Обратный вызов входит в очередь микрозадач и выполняется, печатаяthen1
-
второй раз
resolve
После первого внутриthen
Обратный вызов попадает в очередь микрозадачи, в это время первый внешнийthen
После выполнения всех обратных вызовов второй внешнийthen
Обратные вызовы также вставляются в очередь микрозадач. -
Выполнять микрозадачи, печатать
then1-1
а такжеthen2
, а затем соответственно послеthen
Обратный вызов вставляет очередь микрозадач -
Выполнять микрозадачи, печатать
then1-2
а такжеthen3
, содержание после этого не будет объясняться по одному
Далее мы ставимreturn 1
Измените его, и результат будет совсем другим:
Promise.resolve()
.then(() => {
console.log("then1");
Promise.resolve()
.then(() => {
console.log("then1-1");
return Promise.resolve();
})
.then(() => {
console.log("then1-2");
});
})
.then(() => {
console.log("then2");
})
.then(() => {
console.log("then3");
})
.then(() => {
console.log("then4");
});
когда мыreturn Promise.resolve()
когда, угадай чтоthen1-2
Когда он будет напечатан?
Ответ заключается в том, что печатается последний.
почему вthen
Средняяreturn
Разное, порядок выполнения микрозадач имеет такое большое изменение? Далее следует авторский анализ.
PS:then
** Возвращает новое обещание и будет использовать это обещание дляresolve
Возвращаемое значение, эта концепция должна быть понята в первую очередь. **
Согласно спецификации Promise A+
Согласно спецификации2.3.2,еслиresolve
К нему нужно добавить обещаниеthen
а такжеresolve
.
if (x instanceof MyPromise) {
if (x.currentState === PENDING) {
} else {
x.then(resolve, reject);
}
return;
}
Приведенный выше код взят из написанной от руки реализации Promise.
Тогда согласно спецификации A+, если мы находимся вthen
вернулся вPromise.resolve
Если да, то в очередь будет добавлена еще одна микрозадача, но этот вывод пока не соответствует действительности, поэтому нужно искать другие авторитетные документы.
Согласно спецификации ECMA-262
Согласно спецификации25.6.1.3.2,когдаPromise resolve
Когда обещание сделано, будет создан NewPromiseResolveThenableJob, который является типом Promise Jobs, то есть микрозадач.
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
и задания также будут вызываться один разthen
функционировать, чтобыresolve Promise
, который также генерирует еще одну микрозадачу.
Это источник того, почему микрозадача запускается дважды.
наконец
На этом статья заканчивается, и если у вас есть какие-либо вопросы, вы можете задать их в области комментариев.