自从2015年 ES6(ECMAScript 6)正式发布以来,许多JS新特性让我们的前端开发更加语意化,更加高效。在享受新特性给我们带来的便利的同时,在各类前端框架和业务代码满天飞的同时,我觉得仍有必要不间断地去了解和总结原生JS的底层机制、原理及其优缺点。就从Promise开始。
Promise总结
基本语法
1 | let p = new Promise((resolve, reject) => { |
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
8Promise.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
3npx promises-aplus-test ./ Promise.js
> npx 是 npm 8.5 以上具有的功能。
如果一切顺利,会在一片绿勾之后,得到872 passing (16s)
这样的信息,这说明,你的Promise已经符合PromiseA+规范,即符合基本要求,可以放心使用了。
不间断补充更新中。
–
GoodLuck!