MicrotaskPromisehandlers(处理程序).then、.catch和.finally都是异步的。即使promise被立即解决,.then、.catch和.finally下面的代码也会在这些处理程序之前执行。示例代码如下:letpromise=Promise.resolve();promise.then(()=>alert("promisedone!"));alert("codefinished");//先显示这个alert。如果你运行它,你将首先看到代码完成,然后承诺完成。这很奇怪,因为首先肯定会兑现诺言。为什么.then稍后被解雇?这是怎么回事?微任务队列(Microtaskqueue)异步任务需要妥善管理。为此,ECMA标准规定了PromiseJobs的内部队列,通常称为“微任务队列”(V8术语)。正如规范[1]中所述:队列是先进先出的:先进入队列的任务将先运行。任务队列中的任务只有在JavaScript引擎中没有其他任务运行时才会执行。或者,简单地说,当一个承诺准备就绪时,它的.then/catch/finally处理程序被排队:但它们不会立即执行。当JavaScript引擎执行完当前代码时,它会从队列中取出任务并执行它。这就是为什么“代码完成”在上面的示例中首先显示的原因。Promise处理程序总是经过这个内部队列。如果存在多个.then/catch/finally的链,则它们中的每一个都异步执行。即先入队,直到当前代码执行完毕,之前入队的handler全部执行完毕后,才会执行。如果执行顺序对我们很重要怎么办?我们如何让代码在promise完成后运行?这很简单,只需像这样用.then将其排队:Promise.resolve().then(()=>alert("promisedone!")).then(()=>alert("codefinished"));现在代码按预期执行。Unhandledrejection还记得使用promises[2]错误处理一章中的unhandledrejection事件吗?现在,我们可以确切地看到JavaScript如何发现未处理的拒绝。如果在微任务队列末尾未解决承诺的错误,则会发生“未处理的拒绝”。通常,如果我们预计会发生错误,我们会在promise链中添加一个.catch来处理错误:letpromise=Promise.reject(newError("PromiseFailed!"));promise.catch(err=>alert('caught'));//不会运行:错误已处理window.addEventListener('unhandledrejection',event=>alert(event.reason));但是如果我们忘记添加.catch,那么,当微任务队列清空后,JavaScript引擎会触发如下事件:letpromise=Promise.reject(newError("PromiseFailed!"));//PromiseFailed!window.addEventListener('unhandledrejection',event=>alert(event.reason));如果我们延迟这个错误会发生什么?例如:letpromise=Promise.reject(newError("PromiseFailed!"));setTimeout(()=>promise.catch(err=>alert('caught')),1000);//Error:PromiseFailed!window.addEventListener('unhandledrejection',event=>alert(event.reason));现在,如果我们运行上面的代码,我们将看到PromiseFailed!先,再抓。如果我们不了解微任务队列,我们??可能会想:“为什么unhandledrejection处理程序(handler)会运行?我们已经捕获(catch)并处理了错误!”但是现在我们知道了,当微任务队列中的任务全部完成时才会产生Unhandledrejection:引擎会检查promises,如果其中任何一个promises有一个“rejected”状态,unhandledrejection事件就会被触发。在上面的示例中,添加到setTimeout的.catch也会被触发。它只是在unhandledrejection事件之后触发,所以它不会改变任何东西(不起作用)。总结Promise处理始终是异步的,因为所有promise操作都通过内部“promise作业”队列,也称为“微任务队列”(V8术语)。因此,.then/catch/finally处理程序总是在当前代码完成后调用。如果我们需要保证一段代码在.then/catch/finally之后执行,我们可以将其添加到链式调用的.then中。在大多数JavaScript引擎(包括浏览器和Node.js)中,微任务的概念与“事件循环”和“宏任务”密切相关。由于这些概念与promises没有直接关系,我们将在绘制JavaScript事件循环图:微任务和宏任务一文中介绍它们。现代JavaScript教程:关于开源现代JavaScript的高级教程的优秀介绍。React官方文档推荐的JavaScript学习教程和MDN[3]。免费在线阅读:https://zh.javascript.info参考资料[1]规范:https://tc39.github.io/ecma262/#sec-jobs-and-job-queues[2]使用promises进行错误处理:https://zh.javascript.info/promise-error-handling[3]React官方文档推荐,MDN并行的JavaScript学习教程:https://zh-hans.reactjs.org/docs/getting-started。html#javascript-资源
