10 Promise

80 阅读4分钟
├── Promise 对象
│   ├── Promise 的含义
│   │     └─ 所谓`Promise`,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
│   │     └─ `Promise`对象有以下两个特点。
│   │         └─ (1)对象的状态不受外界影响。
│   │         └─ (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
│   │     └─ 
│   ├── 基本用法
│   │     └─ `Promise`对象是一个构造函数,用来生成`Promise`实例。
│   │     └─ `then`方法可以接受两个回调函数作为参数。第一个回调函数是`Promise`对象的状态变为`resolved`时调用,第二个回调函数是`Promise`对象的状态变为`rejected`时调用。
│   ├── Promise.prototype.then()
│   │     └─ Promise 实例具有`then`方法,也就是说,`then`方法是定义在原型对象`Promise.prototype`上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,`then`方法的第一个参数是`resolved`状态的回调函数,第二个参数是`rejected`状态的回调函数,它们都是可选的。
│   ├── Promise.prototype.catch()
│   │     └─ `Promise.prototype.catch()`方法是`.then(null, rejection)``.then(undefined, rejection)`的别名,用于指定发生错误时的回调函数。
│   │     └─ Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。
│   ├── Promise.prototype.finally()
│   │     └─ `finally()`方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
│   │     └─ `finally`方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是`fulfilled`还是`rejected`。这表明,`finally`方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。`finally`本质上是`then`方法的特例。
│   ├── Promise.all()
│   │     └─ `Promise.all()`方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
│   │     └─ `Promise.all()`方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
│   │     └─ 当每个 Promise 实例 rejected 但是自己有 catch 方法, 这样 `Promise.all()`方法参数里面实例就会是`resolved`状态, 那么就会走到 then 而不是 catch
│   ├── Promise.race()
│   │     └─ `Promise.race()`方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
│   │     └─ const p = Promise.race([p1, p2, p3]); 只要`p1``p2``p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给`p`的回调函数。
│   ├── Promise.allSettled()
│   │     └─ `Promise.allSettled()`方法,用来确定一组异步操作是否都结束了(不管成功或失败)。所以,它的名字叫做”Settled“,包含了”fulfilled“和”rejected“两种情况。
│   │     └─ `results`的每个成员是一个对象,对象的格式是固定的,对应异步操作的结果。 {status: 'fulfilled', value: value}
│   │     └─ 成员对象的`status`属性的值只可能是字符串`fulfilled`或字符串`rejected`,用来区分异步操作是成功还是失败。如果是成功(`fulfilled`),对象会有`value`属性,如果是失败(`rejected`),会有`reason`属性,对应两种状态时前面异步操作的返回值。
│   ├── Promise.any()
│   │     └─ 该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
│   │     └─ 只要参数实例有一个变成`fulfilled`状态,包装实例就会变成`fulfilled`状态;如果所有参数实例都变成`rejected`状态,包装实例就会变成`rejected`状态。
│   │     └─ `Promise.any()`不会因为某个 Promise 变成`rejected`状态而结束,必须等到所有参数 Promise 变成`rejected`状态才会结束。
│   │     └─ 其中只要有一个变成`fulfilled``Promise.any()`返回的 Promise 对象就变成`fulfilled`。如果所有三个操作都变成`rejected`,那么`await`命令就会抛出错误。
│   ├── Promise.resolve()
│   │     └─ 有时需要将现有对象转为 Promise 对象,`Promise.resolve()`方法就起到这个作用。
│   │     └─ `Promise.resolve()`方法的参数分成四种情况。
│   │         └─ **(1)参数是一个 Promise 实例** 如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。
│   │         └─ **(2)参数是一个 `thenable`对象** `thenable`对象指的是具有`then`方法的对象 `Promise.resolve()`方法会将这个对象转为 Promise 对象,然后就立即执行`thenable`对象的`then()`方法。
│   │         └─ **(3)参数不是具有 `then()`方法的对象,或根本就不是对象** 如果参数是一个原始值,或者是一个不具有`then()`方法的对象,则`Promise.resolve()`方法返回一个新的 Promise 对象,状态为`resolved`。
│   │         └─ **(4)不带有任何参数** `Promise.resolve()`方法允许调用时不带参数,直接返回一个`resolved`状态的 Promise 对象。
│   ├── Promise.reject()
│   │     └─ `Promise.reject(reason)`方法也会返回一个新的 Promise 实例,该实例的状态为`rejected`。
│   ├── 应用
│   │     └─ 加载图片
│   │         └─ 我们可以将图片的加载写成一个`Promise`,一旦加载完成,`Promise`的状态就发生变化。
│   │     └─ Generator 函数与 Promise 的结合
│   │         └─ 使用 Generator 函数管理流程,遇到异步操作的时候,通常返回一个`Promise`对象。
│   ├── Promise.try()
│   │         └─ try { database.users.get({id: userId}) .then(...) .catch(...)} catch (e) {// ...}
│   │         └─ Promise.try(() => database.users.get({id: userId})).then(...).catch(...)
│   │         └─ `Promise.try`就是模拟`try`代码块,就像`promise.catch`模拟的是`catch`代码块。