Когда я вызываю это обещание, результат не соответствует последовательности вызовов функций. .then
Приходит до того , как .catch
, несмотря на то, обещание с .then
было называться после. В чем причина этого?
const verifier = (a, b) =>
new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));
verifier(3, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
verifier(5, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
выход
node promises.js
response: true
error: false
javascript
node.js
Густаво Алвес
источник
источник
Ответы:
Это классный вопрос, чтобы разобраться в нем.
Когда вы это сделаете:
verifier(3,4).then(...)
который возвращает новое обещание, для которого требуется еще один цикл возврата к циклу событий, прежде чем это вновь отклоненное обещание сможет запустить
.catch()
следующий обработчик. Этот дополнительный цикл дает следующую последовательность:verifier(5,4).then(...)
шанс запустить его
.then()
обработчик перед предыдущей строкой,.catch()
потому что он уже был в очереди до того, как.catch()
обработчик из первой попадет в очередь, а элементы запускаются из очереди в порядке FIFO.Обратите внимание, что если вы используете
.then(f1, f2)
форму вместо.then().catch()
, она запускается тогда, когда вы этого ожидаете, потому что нет дополнительных обещаний и, следовательно, дополнительных тиков:const verifier = (a, b) => new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false))); verifier(3, 4) .then((response) => console.log("response (3,4): ", response), (error) => console.log("error (3,4): ", error) ); verifier(5, 4) .then((response) => console.log("response (5,4): ", response)) .catch((error) => console.log("error (5,4): ", error));
Обратите внимание, я также пометил все сообщения, чтобы вы могли видеть, из какого
verifier()
вызова они приходят, что значительно упрощает чтение вывода.Спецификация ES6 для заказа обратного вызова обещаний и более подробное объяснение
Спецификация ES6 сообщает нам, что «задания» обещаний (поскольку они вызывают обратный вызов из
.then()
или.catch()
) выполняются в порядке FIFO в зависимости от того, когда они вставлены в очередь заданий. Он конкретно не называет FIFO, но указывает, что новые задания вставляются в конец очереди, а задания запускаются с начала очереди. Это реализует порядок FIFO.PerformPromiseThen (который выполняет обратный вызов из
.then()
) приведет к EnqueueJob, что является тем, как запланировано фактическое выполнение обработчика разрешения или отклонения. EnqueueJob указывает, что ожидающее задание добавляется в конец очереди заданий. Затем операция NextJob извлекает элемент из начала очереди. Это обеспечивает порядок FIFO при обслуживании заданий из очереди заданий Promise.Итак, в примере в исходном вопросе мы получаем обратные вызовы для
verifier(3,4)
обещания иverifier(5,4)
обещания, вставленного в очередь заданий в том порядке, в котором они были запущены, потому что оба этих исходных обещания выполнены. Затем, когда интерпретатор возвращается в цикл обработки событий, он сначала беретverifier(3,4)
задание. Это обещание отклонено, и вverifier(3,4).then(...)
. Таким образом, он отклоняет обещание, котороеverifier(3,4).then(...)
вернулось, и в результатеverifier(3,4).then(...).catch(...)
обработчик вставляется в jobQueue.Затем он возвращается в цикл обработки событий, и следующее задание, которое он извлекает из jobQueue, - это
verifier(5, 4)
задание. У него есть обработанное обещание и обработчик разрешения, поэтому он вызывает этот обработчик. Это приводитresponse (5,4):
к отображению вывода.Затем он возвращается в цикл обработки событий, и следующее задание, которое он извлекает из jobQueue, - это
verifier(3,4).then(...).catch(...)
задание, в котором оно выполняется, и это приводитerror (3,4)
к отображению вывода.Это потому, что
.catch()
в 1-й цепочке на один уровень обещания глубже, чем.then()
во 2-й цепочке, которая вызывает упорядочивание, о котором вы сообщили. И это потому, что цепочки обещаний переходят с одного уровня на другой через очередь заданий в порядке FIFO, а не синхронно.Общие рекомендации относительно использования этого уровня детализации планирования
К вашему сведению, в общем, я стараюсь писать код, который не зависит от этого уровня подробных знаний о времени. Хотя это любопытно и иногда полезно понимать, это хрупкий код, поскольку простое, казалось бы, безобидное изменение кода может привести к изменению относительного времени. Итак, если время между двумя подобными цепочками имеет решающее значение, я бы предпочел написать код таким образом, чтобы он задавал время так, как я хочу, чем полагаться на этот уровень детального понимания.
источник
.then()
оно должно возвращать новое обещание, которое само должно асинхронно разрешать / отклонять в будущем тике, что и приводит к этому упорядочиванию. Вы знаете какую-либо реализацию, в которой не используется упорядочение конкурирующих обратных вызовов FIFO?await
).PerformPromiseThen
приведет к тому,EnqueueJob
как будет запланирован вызов обработчика разрешения или отклонения. EnqueueJob указывает, что ожидающее задание добавляется в конец очереди заданий. Затем операция NextJob извлекает элемент из начала очереди. Это обеспечивает порядок FIFO в очереди заданий Promise.await
в ES11? Достаточно ссылки. Благодарность!!Promise.resolve() .then(() => console.log('a1')) .then(() => console.log('a2')) .then(() => console.log('a3')) Promise.resolve() .then(() => console.log('b1')) .then(() => console.log('b2')) .then(() => console.log('b3'))
Вместо вывода a1, a2, a3, b1, b2, b3 вы увидите a1, b1, a2, b2, a3, b3 по той же причине - каждый затем возвращает обещание и переходит в конец цикла событий очередь. Итак, мы видим эту «гонку обещаний». То же самое и с вложенными обещаниями.
источник