es6-promise

自从2015年 ES6(ECMAScript 6)正式发布以来,许多JS新特性让我们的前端开发更加语意化,更加高效。在享受新特性给我们带来的便利的同时,在各类前端框架和业务代码满天飞的同时,我觉得仍有必要不间断地去了解和总结原生JS的底层机制、原理及其优缺点。就从Promise开始。

Promise总结

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let p = new Promise((resolve, reject) => {
console.log(1)
setTimeout(() => {
resolve(2);
}, 1000);
})

p.then(data => {
console.log(data);
}, err => {
console.log(err);
})

console.log(3);

//输出:
1
3
2

其中 1 和 3 是立即输出,2 是1秒后输出。

Promise的本质

它是一个类。它是异步编程的一种解决方案。
它的链式调用方式,在一定程度上可以解决JS中的多层异步回调嵌套问题(也叫回调地狱)。

Promise的特征

1 . 一个Promise对象有三个状态:pending,fulfilled,rejected。
只能当状态是pending时,这个状态才能改变,并且状态一旦发生改变,就不能再改变。

2 . Promise实例化时接受一个函数作为参数,这个函数会立即执行。
这个函数暴露两个参数,分别是resolve,reject,这两个参数同样也是函数。

3 . 每个Promise对象都有一个then方法。

4 . resolve和reject都接收一个参数,这个参数将被在内部进行一些必要处理,其返回结果会传到下一个then中。

5 . 必须在这个Promise实例中调用resolve或则reject或者throw new Error,才会往下走,即then中的方法才会被执行。

6 . 一个Promise对象可以多次then,也可以连续then(链式调用),每次then都会返回一个新的Promise对象。

7 . then也接收两个参数,是两个回调函数,分别对应处理成功和失败的业务。

8 . then的回调函数中,使用return进入下一个then的成功、使用throw new Error 等报错,进入下一个then的失败。不显示写return,则默认return undefined,也是进入下一个then的成功。

9 . then是微任务,所以then中的方法会在同步代码执行后再执行。

10 . 如果Promise实例中resolve了一个Promise,Promise内部会取这个Promise的then的结果,如果还是一个Promise,继续取,直到获得一个非Promise的值,然后把这个值返回。

11 . Promise的then可以穿透,即如果中间的then没有写成功或者失败的处理,则结果会一直往下传,直到有then处理。

Promise实例上的方法和静态方法

Promise实例上的方法:

  • then
    处理回调的函数。then的链式调用,是异步有序的,写在前面的会先执行。
  • catch
    本质是 .then(null, rejectCallback) 的别名,用于处理错误。
  • finally
    ES2018 中的新特性。不管Promise成功还是失败,都会执行的操作。

Promise静态方法:

  • resolve
    将现有对象转为Promise对象的快捷方法。
  • reject
    产生一个状态为 rejected 的Promise实例。
  • all
    将多个Promise实例装包成一个Promise实例,同步获取多个异步操作的结果,只有所有Promise实例的状态都为 fulfilled,这个Promise才会成功,并且返回一个数组,里面按序存放异步操作的结果。只要一个Promise被reject,整个Promise都reject。
  • race
    将多个Promise实例包装成一个Promise实例,谁先改变状态,整个Promise就采用谁的状态和返回值。
  • any
    目前是一个stage3提案。接受一组Promise实例,如果谁先变成 fulfilled,整个Promise fulfilled,如果都 rejected,整个都失败。

Promise的缺点

Promise不能彻底解决回调地狱,因为它也是基于回调来实现的。

解决方案:
结合async+await,彻底解决异步回调地狱问题。

自己实现一版Promise

现在的大部分IDE和浏览器都已经内置原生Promise,不过你也可以不使用原生Promise,选择自己写一个Promise。

但如果你的Promise想跟原生Promise混用,或者想让别人使用,最好先通过 promiseA+规范 的测试。

如何测试自己的Promise是否符合PromiseA+规范

  • step1. 在代码中添加测试代码
    在自己的 Promise.js 里,给Promise添加一个deferred静态方法,在里面new一个自己的Promise 实例,把自己的Promise实例和实例上的resolve、reject挂上去:

    1
    2
    3
    4
    5
    6
    7
    8
    Promise.deferred = () => {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
    })
    return dfd;
    }
  • step2. 安装 promsises-aplus-tests 插件

    1
    npm i -D primises-aplus-tests
  • step3. 运行脚本

    1
    2
    3
      npx promises-aplus-test ./ Promise.js

    > npx 是 npm 8.5 以上具有的功能。

如果一切顺利,会在一片绿勾之后,得到872 passing (16s)这样的信息,这说明,你的Promise已经符合PromiseA+规范,即符合基本要求,可以放心使用了。

不间断补充更新中。


GoodLuck!