Promise
Promise 与事件循环
可以简单的认为:
立即 resolve 的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。
1 | setTimeout(() => { |
Promise 内的 return
- 与普通函数无二致:一旦遇到 return 函数便执行完毕,跳出。
- 在没有遇到
return之前,Promise 内的代码能一直执行。
.then()/.catch() 返回值
两个方法返回的都是一个新的 Promise 对象,可以轻易实现 回调链。
回调函数没有显示返回值
.then 返回一个新的 Promise 对象,该 Promise 对象的:
- [[PromiseStatus]] 为
resolved - [[PromiseValue]] 为
undefined
1 | const a = new Promise((resolve) => {resolve(1)}); |
回调函数返回非 Promise 值
.then() 返回一个新的 Promise 对象,该对象的:
- [[PromiseStatus]] 为
resolved - [[PromiseValue]] 为
then内回调函数的返回值
1 | const obj = {key: 'value'}; |
回调函数返回值为一个新的 Promise
.then() 返回值为一个 Promise 对象,该 Promise 对象即为回调函数返回的 Promise 对象。
1 | const a = new Promise((resolve) => { resolve(1); }); |
Promise 错误处理
Promise 错误能被 .then() 或 .catch() 处理,这两个对错误的类似于try...catch的错误处理。
未处理的 reject
一个 Promise 内执行了 reject, 该 Promise 对象的状态由 pending 变为 rejected,此时根据是否有 then() (第二个回调函数参数)或 catch() 来处理这个 rejection 会有不同的表现:
在 .then() (第二个回调函数参数) 或 .catch() 中处理了 rejection
JavaScript Runtime 不会报 Uncaught (in Promise) 错误
一直到代码执行完毕 rejection 都没有处理
JavaScript Runtime 报 Uncaught (in Promise) 错误
Runtime 不知道何处会有处理的逻辑,所以在最后才会通报1中的错误
代码会继续执行直到完毕,不退出
注意: 以后如果有未处理的rejection 会导致程序 non-zero exit(在诸如 node server 这些运行时是致命的),所以确保 Promise 的错误有处理。
Promise 内同步错误
错误在 resolve() 或 reject() 之前
Promise 内的运行错误相当于: reject(error) + return
有以下几个特征:
- Promise 内的代码 不再往下执行
- 相当于立即执行
reject(error)并return(然后根据有无处理 rejection 就划归为上文相关问题)
1 | // bbb 未定义 |
错误在 resolve() 或 reject() 后
Promise 内的运行错误相当于: reject(error) + return
特征:
- resolve() 与 reject() 后的代码继续执行,直到遇到错误或
return - 错误被忽略,不会被 Runtime 捕获
1 | // foo 未定义 |
Promise.all([p1, p2, p3])
有以下几点需要注意:
- 接受一个具有 Iterator 接口的可遍历类型(典型的: 如数组)作为参数
Promise.all()会遍历传入的可遍历结构,如果其中元素(p1, p2, p3…)不是 Promise,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例- 返回一个新的 Promise 对象
关于 Promise 的状态与数据:
- 只有 p1, p2, p3 的状态都变成
fulfilled,新 Promise 对象的状态才会变成fulfilled,此时 p1, p2, p3 的返回值(有次序的)组成一个数组,传递给 p 的回调函数。 - 只要 p1, p2, p3 之中有一个被 rejected,p 的状态就变成 rejected,此时第一个被 reject 的实例的返回值,会传递给新 Promise 对象的回调函数。
Promise.race([p1, p2, p3])
与 Promise.all() 类似,但是新 Promise 的状态与回调函数数据来源于 p1, p2, p3 中最先状态发生变化的那个。
Promise.resolve() —— 万物皆可 Promise
(1) 参数是一个 Promise 实例
如果参数是 Promise 实例,那么 Promise.resolve 将不做任何修改、原封不动地返回这个实例。
(2) 参数是一个thenable对象
thenable 对象指的是具有 then 方法的对象(在 Java 里通常形象地说是一个类实现了 thenable 接口),比如下面这个对象。
1 | // 便于理解,将其视为一个伪 Promise |
(3) 参数是一个不具有 then 方法的对象,或者根本就不是对象
返回一个新的 Promise 对象
1. [[PromiseStatus]] 为 Resolved
2. [[PromiseValue]] 为传入的参数
(4) 不带入任何参数
相当于 (3)中传入 undefined
两个额外的好用方法
1 | // 用于回调链尾部的收尾处理 |