С обещанием, почему браузеры возвращают отклонение дважды, а не разрешение дважды?

10

У меня проблемы с пониманием javaScript promises. Я написал следующий код:

var p = new Promise(function(resolve,reject){

    reject(Error("hello world"));
});

setTimeout(()=>p.catch(e=>console.log(e)),5000);

Я сразу вижу это в моей консоли разработчика Chrome: введите описание изображения здесь

Но после того, как я подожду 5 секунд, сообщение автоматически изменится на черный, как показано ниже: введите описание изображения здесь

Я никогда раньше не видел такого поведения между моим кодом javaScript и консолью разработчика, где мой код javaScript может «изменять существующее содержимое» в консоли разработчика.

Поэтому я решил посмотреть, возникает ли такая же ситуация resolve, написав этот код:

var p = new Promise(function(resolve,reject){

    resolve("hello world");
});

setTimeout(()=>p.then(e=>console.log(e)),5000);

Но в этой ситуации моя консоль разработчика ничего не показывает, пока через 5 секунд она не распечатывается hello world.

Почему resolveи rejectобработаны таким образом , по- разному с точки зрения , когда они вызываются?


EXTRA

Я также написал этот код:

var p = new Promise(function(resolve,reject){

    reject(Error("hello world"));
});

setTimeout(()=>p.catch(e=>console.log("errors",e)),5000);
setTimeout(()=>p.catch(e=>console.log("errors 2",e)),6000);
setTimeout(()=>p.catch(null),7000);

Это приводит к нескольким выводам на консоль разработчика. Ошибка красного цвета в момент времени 0, красный цвет errors hello worldстановится черным в момент времени 5 секунд с текстом , затем новое сообщение об ошибке в момент времени 6 секунд errors 2 hello world, затем красное сообщение об ошибке в момент времени 7 секунд. Теперь я очень озадачен тем, сколько раз rejectдействительно вызывается .... Я потерян ...

Джон
источник
1
Просто в стороне: var p = new Promise(function(resolve,reject){ reject(Error("hello world")); });может быть более идиоматически и кратко написано как var p = Promise.reject(Error("hello world"));:-)
TJ Crowder
1
Внушительный вопрос.
TJ Crowder

Ответы:

11

Вау, это действительно круто. Я никогда не видел, чтобы консоль делала это раньше. ( Хотя есть и другие формы динамического поведения, так что ...) Вот что происходит:

В первом случае выполнение кода за пределами setTimeoutкода вашего обратного вызова завершается, и стек выполнения возвращается так, что выполняется только «программный код » (как его называет спецификация Promises / A +), а не пользовательский код JavaScript (на данный момент). В этот момент обещание отклоняется, и ничто не обработало отклонение, поэтому это необработанное отклонение, и devtools сообщает вам об этом как таковое.

Затем , через пять секунд, ваш обратный вызов запускается и подключает обработчик отклонения. На данный момент отказ больше не обрабатывается. Очевидно, Chrome / V8 / devtools работают вместе, чтобы удалить необработанное предупреждение об отказе от консоли. Вместо этого вы видите то, что вы выводите через обработчик отклонений console.log. Если вы подключите обработчик отклонения раньше, вы не получите эту необработанную ошибку отклонения.

Этого не происходит с выполнением, потому что отсутствие обработки выполнения не является ошибкой. Не обрабатывается отказ.

TJ Crowder
источник
1
О, это имеет смысл. Я заметил, что FireFox обрабатывает это немного по-другому. Но хорошо, теперь имеет больше смысла.
Джон
1
Я написал то же самое в ответе, но ТАК загрузил ваш, поэтому я не разместил свой. Хорошее объяснение! +1
ФЗ