[关闭]
@yangfch3 2017-05-25T15:47:47.000000Z 字数 4029 阅读 2293

Promise

JavaScript


Promise 与事件循环

可以简单的认为:

立即 resolve 的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

  1. setTimeout(function() {
  2. console.log(1)
  3. }, 0);
  4. new Promise(function executor(resolve) {
  5. console.log(2);
  6. for (var i = 0; i < 10000; i++) {
  7. i == 9999 && resolve();
  8. }
  9. console.log(3);
  10. }).then(function() {
  11. console.log(4);
  12. });
  13. console.log(5);
  14. // 2 3 5 4 1
  15. // 分析
  16. // 2 3 5
  17. // 本轮事件循环结束
  18. // 4
  19. // 本轮事件循环结束时 `.then()`
  20. // 下一轮事件循环开始
  21. // 1

Promise 内的 return

  1. 与普通函数无二致:一旦遇到 return 函数便执行完毕,跳出
  2. 在没有遇到 return 之前,Promise 内的代码能一直执行

.then()/.catch() 返回值

两个方法返回的都是一个新的 Promise 对象,可以轻易实现 回调链

回调函数没有显式返回值

.then() 返回一个新的 Promise 对象,该 Promise 对象的:

  1. [[PromiseStatus]]resolved
  2. [[PromiseValue]]undefined
  1. var a = new Promise((resolve) => {resolve(1)});
  2. var b = a.then((value) => {console.log(value + 1)})
  3. b;
  4. // Promise {
  5. // [[PromiseStatus]]: "resolved",
  6. // [[PromiseValue]]: undefined
  7. // }

回调函数返回非 Promise 值

.then() 返回一个新的 Promise 对象,该 Promise 对象的:

  1. [[PromiseStatus]]resolved
  2. [[PromiseValue]]then 内回调函数返回的值
  1. var obj = {key: 'value'};
  2. var a = new Promise((resolve) => {resolve(1)});
  3. var b = a.then((value) => {console.log(value + 1)})
  4. b;
  5. // Promise {
  6. // [[PromiseStatus]]: "resolved",
  7. // [[PromiseValue]]: {
  8. // key: 'value'
  9. // }
  10. // }

回调函数返回值为又一个新的 Promise

.then() 返回值为一个 Promise 对象,该 Promise 对象即为回调函数返回的 Promise 对象。

  1. var a = new Promise((resolve) => {resolve(1)});
  2. var b = a.then((value) => {return new Promise((resolve, reject) => {resolve(value + 1)})});
  3. b;
  4. // Promise {
  5. // [[PromiseStatus]]: "resolved",
  6. // [[PromiseValue]]: 2
  7. // }

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

有以下几个特征:

  1. Promise 内代码 不再往下执行
  2. 相当于立即执行 reject(error)return(然后根据有无处理 rejection 就化归为上文相关问题)
  1. // bbb 未定义
  2. var a = new Promise((resolve, reject) => {
  3. console.log(bbb);
  4. console.log('aaa');
  5. resolve(1);
  6. });
  7. // 输出
  8. // Uncaught (in promise) ReferenceError: bbb is not defined
  9. // at Promise (<anonymous>:1:55)
  10. // at Promise (<anonymous>)
  11. // at <anonymous>:1:9
  12. a;
  13. // 输出
  14. // Promise {
  15. // [[PromiseStatus]]: "rejected",
  16. // [[PromiseValue]]: ReferenceError: bbb is not defined
  17. // at Promise (<anonymous>:1:55)
  18. // at Promise (<anonymous>)
  19. // …
  20. // }

错误在 resolve() 或 reject() 后

Promise 内的运行错误相当于:reject(error) + return

特征:

  1. resolve()reject() 后的代码继续执行,直到遇到错误或 return
  2. 错误被忽略,不会被 Runtime 捕获
  1. // bbb 未定义
  2. var a = new Promise((resolve, reject) => {resolve(1);console.log(bbb);console.log('aaa');});
  3. // Runtime 并没有通报 console.log(bbb) 这里的错误
  4. a;
  5. // 输出
  6. // Promise {
  7. // [[PromiseStatus]]: "resolved",
  8. // [[PromiseValue]]: 1
  9. // }

Promise.all([p1, p2, p3])

有以下几点需要注意:

  1. 接受一个具有 Iterator 接口的可遍历类型(典型的:如数组)作为参数
  2. Promise.all() 会遍历传入的可遍历结构,如果其中元素(p1, p2, p3...)不是 Promise,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例
  3. 返回的是一个新的 Promise 对象

关于 Promise 的状态与数据:

  1. 只有 p1、p2、p3 的状态都变成 fulfilled,新 Promise 对象的状态才会变成 fulfilled,此时 p1、p2、p3 的返回值(有次序地)组成一个数组,传递给p的回调函数
  2. 只要 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
  2. let thenable = {
  3. then: function(resolve, reject) {
  4. // 在这里可以 resolve 与 reject
  5. }
  6. };

Promise.resolve 方法会将这个对象转为 Promise 对象,然后就立即执行 thenable 对象的 then 方法。then 方法可以接收 resolvereject 做为参数,改变

  1. let p1 = Promise.resolve(thenable);
  2. p1;
  3. // Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

(3)参数不是具有 then 方法的对象,或根本就不是对象
返回一个新的 Promise 对象

  1. [[PromiseStatus]]Resolved
  2. [[PromiseValue]] 为传入的参数

(4)不带任何参数
相当于 (3)中传入 undefined

两个额外的好用方法

  1. // 用于回调链尾部的收尾处理
  2. Promise.prototype.done = function (onFulfilled, onRejected) {
  3. this.then(onFulfilled, onRejected)
  4. .catch(function (reason) {
  5. // 抛出一个全局错误
  6. setTimeout(() => { throw reason }, 0);
  7. });
  8. };
  9. // 用于在回调链尾部接一个普通的回调函数
  10. Promise.prototype.finally = function (callback) {
  11. let P = this.constructor;
  12. return this.then(
  13. value => P.resolve(callback()).then(() => value),
  14. reason => P.resolve(callback()).then(() => { throw reason })
  15. );
  16. };
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注