Объясните этот порядок выполнения setTimeout и обработчиков catch - PullRequest
0 голосов
/ 24 января 2020

У меня есть это сомнение относительно порядка выполнения функций Timer, микрозадач и прослушивателей событий:

let promise = Promise.reject("Err@!");

setTimeout(() => {
        promise.catch(er => console.log(er, "Caught !"));         // (1)
});

window.addEventListener('unhandledrejection', event => console.log("Unhandled Rejection !", event.reason));  //  (2)

// Output 
// >> Unhandled Rejection ! Err@!
// >> Err@! Caught !

В этом случае отклоненное обещание попадает в событие Unhandled Rejection, а затем перехватывается внутри .catch () setTimeout, причина этого в том, что

«необработанное отклонение» происходит, когда ошибка обещания не обрабатывается в конце очереди микрозадачи (https://javascript.info/microtask-queue#unhandled -отклонение )

Теперь рассмотрим другой случай:

let promise = Promise.reject("Err@!");

setTimeout(() => {       // (1)  ,gets called first

    setTimeout(function () {  // (3) , gets called at last , (after (2))
        promise.catch(er => console.log("caught ", er  ))
    })

});

setTimeout(function () {      // (2) , gets called after (1)
    window.addEventListener('unhandledrejection', event => console.log("Unhandled Rejection !", event.reason));
})

// Output 
//>>  caught  Err@!

В этом случае обработчик перехватывает обещание во вложенном setTimeout, даже когда во втором setTimeout очередь микротасков пуста, а Отклоненное обещание все еще не обработано слушателем события окна ...

Почему так?

1 Ответ

1 голос
/ 24 января 2020

К тому моменту, как обещание отклоняется (без обработки), обработчик unhandledrejection еще не был присоединен, поэтому он не обрабатывает случай. Вы можете прикрепить обработчики .catch и .then в любое время, и если Обещание уже разрешено / отклонено, они будут срабатывать немедленно (в микрозадаче).

 // first example
 1) synchronous execution
  - promise rejected
  - timeout set 
  - unhandledrejection event handler attached
 2) microtasks
  - promise rejects
 3) macrotask
  - timeout triggers
    -> .catch handler gets attached
 4) microtasks
   .catch gets executed

 // second example
 1) synchronous execution
 - timers get attached
 - promise rejects
 2) microtasks
 - promise rejected
 3) macrotasks
 - timer 1 done
   - timer 3 started
 - timer 2 done 
    - unhandledrejection handler added
...