Promise的学习

133 阅读8分钟

哈喽大家好,我是阿锋,一个前端小菜鸟。今天给大家带来一个Promise的学习总结。话不多说直接上代码。

前言

首先,我们需要明白。学习一个东西我们得先知道它是什么?为什么需要它?怎么做?也就是著名的三段论。

Promise是什么?

那么我们来想想,Promise是什么??这里我们引用阮一峰大佬ES6中对Promise的解释。如果没看过的,可以去看看。从这里我们可以看出。Promise是一种异步编程解决方案。是一个容器,里面存的是未来某个时间点完成某一件事(一般指网络请求)后给你的东西(一般指网络请求完成后给你返回的数据或者提示,不管是成功还是失败)。

为什么需要Promsie

我们已经知道了Promise是一个什么东西了,那么我们现在来讨论为什么需要它。

这里我们写一段代码,模拟一下以前的网络请求

image.png 这是打印的结果

image.png

通过代码我们可以看到这种方式有缺点:

  1. 如果这个请求接口的函数是自己写的:那么你还得去思考成功和失败回调函数的名字。
  2. 如果这个请求接口的函数不是自己写的:在使用它的时候还得去看别人的源码或者文档,看别人用的哪个名字。 这样下来,我们开发的沟通成本以及效率,代价都比较高。

所以为了提高开发效率降低沟通成本。Promise就出现了。

我们将上面代码用Promise改造一下

image.png 打印结果

image.png

这里我们可以看到,我们不用去考虑别人使用的回调函数的名字。我们只需要知道,它返回一个Promise,那么我们就可以使用Promise的相关api去拿到结果。再进行一系列的操作。

这样以来,开发效率提高了。一看是Promise,我就知道该怎么用了。沟通成本也降低了。只要去看过一些Promise教程,那么简单的使用肯定是可以用的。

Promise相关api学习

上面我们讨论了Promise是什么,为什么需要它,那么接下来我们就来学习Promise的相关api。

Promise本身

Promise是一个类,它翻译成中文的意思是:许诺/承诺/期约

当通过new创建一个Promise的实例时,会传入一个回调函数,称为executor,这个回调函数会立即执行。同时这个回调函数会有两个参数(resolve/reject),两个参数也都是回调函数。调用resolve会被Promise的then方法第一个回调捕获,调用reject会被Promise的then方法第二个回调函数捕获。

Promise还有三种状态:

  • pending: Promise的初始状态,调用excutor且没有调用resolve/reject的时候就处于这个状态。
  • fulfilled: 意味着操作成功完成,执行了resolve时处于这个状态
  • rejected: 意味着操作失败,执行了reject时处于这个状态

我们来看看Promise的代码结构

image.png

image.png

通过打印结果可以看出,当new Promise传入了executor回调函数的时候,executor回调函数立即执行了。

我们用then方法捕获一下resolve回调看看发生了什么。

image.png

image.png

通过打印,我们可以看到当执行了resolve回调函数的时候,被then方法的第一个回调函数捕获了。同时在调用resolve的时候,Promise的状态变成了fulfilled。同理:执行reject,会被then方法的第二个回调捕获,Promise的状态变成rejected(抛出错误也会被then方法的第二个参数捕获).

image.png

image.png

同时!!!一旦状态确定了之后就不可以更改了。意味着当我们调用了resolve/reject之中任意一个回调后,再次调用另一个,是不会成功调用的。

image.png

image.png

resolve的参数

resolve有三种参数可以传,每种参数对应的处理逻辑不一样。

1. 当resolve传的是普通的值或者是对象,那么会直接被then方法的第一个回调函数捕获.

image.png

image.png

2. 当resolve传的是一个新的Promise,那么新的Promise状态决定旧的Promise的状态。

传入的Promise调用resolve

image.png

image.png

传入的Promise调用reject

image.png

image.png

  1. 当resolve传的是一个实现了thenable的对象(也就是对象有一个then方法。) 传入的对象then方法调用resolve

image.png

image.png

传入的对象then方法调用reject

image.png

image.png

then方法

then方法其实是Promise.prototype上的方法。每一个new Promise的实例都可以调用这个方法。他有两个参数且每个参数都是回调函数。第一个参数是Promise实例状态变成fulfilled时回调的函数,第二个参数是Promise的状态变成rejected时回调的函数。(上面已经有打印的结果,可以去看看,主要讲的是后面的)

then方法可以多次调用

image.png

image.png

then方法执行完了之后是会返回一个新的Promise的。如果有显示的返回。那么返回的这个值会作为一个新Promise调用resolve的参数。有点绕,直接看代码吧

image.png

image.png

所以Promise才可以链式调用,因为then执行完之后是会返回一个新的Promise的。同时,我们又回到了resolve的参数问题了。这里就不再继续说了。这里值得注意的是,只有抛出错误,才会被then方法的第二个参数捕获。

image.png

还有一点需要注意,then方法的第二个回调函数里返回的参数和第一个是一样的,只有在抛出错误的是才会被新Promise的then方法第二个回调函数捕获。

image.png

image.png

image.png

catch方法

catch其实是then方法第二个回调参数的语法糖。因为在实际开发中。我们更习惯这样写

image.png

image.png

抛出错误也会被catch方法捕获

image.png

同理,catch也可以多次调用

image.png

image.png

catch方法也有返回值,它的返回值状态和then方法的一致

image.png

catch方法的捕获有些特殊,它只捕获第一个跑出错误或者第一个调用reject方法。

image.png

image.png

finally

finally方法是ES9(ES2018)新增的一个方法,它表示无论Promise的状态是fulfilled还是rejected,它都会执行。

image.png

image.png

前面我们讲到的then、catch、finally方法都是实例方法。都是在Promise.prototype上的。接下来我们来讲一下Promise的类方法

resolve类方法

有时候我们已经有一个结果,但是我们想把它包装成一个Promise,这时候我们就可以用Promise的resolve类方法

image.png

image.png

这里又回到了resolve的参数问题上了。所以不再细说了。

reject方法

reject方法和resolve方法是差不多的,不过是将Promise的状态变成了rejected.无论传的是什么值都会变成rejected。

image.png

image.png

all方法

all方法是将一个或者多个Prmise放在一起,形成一个新的Promise 新的Promise的状态由这些Promise的状态决定

  • 当所有的Promise的状态都变成fulfilled时,新的Promise的状态变成fulfilled,并将结果组成一个数组返回
  • 当有一个Promise的状态变成了rejected时,新的Promise的状态立即变成rejected,并返回结果。

image.png

image.png

allSettled

all方法有一个缺陷:就是当有一个Promise的状态变成rejected的时候,其他的Promise的状态就不会有结果了。 为了解决这个问题,ES11就新增了一个api叫allSettled

allSettled方法也是将一个或者多个Promise包裹起来,然后形成一个新的Promise。

  • 该方法会在所有的Promise都有结果的时候才会有结果,不论是fulfilled,rejected
  • 并且新的Promise的状态都是fulfilled。

image.png

image.png

通过打印我们可以看到,allSettled方法的结果是一个数组,数组里面是所有Promise的结果的对象,每一个对象里面都有status、value/reason 字段。

race

race翻译成中文就是竞赛的意思。表示谁先有结果新Promise就用谁的结果

image.png

image.png

any

any方法和race方法是类似的

  • any方法会等一个fulfilled状态,新的Promise才会有状态
  • 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态;

image.png

image.png

结束语

以上就是我在看了阮一峰大佬、coderwhy老师的视频的时候个人对Promise的总结。当然,大部分是跟着coderwhy老师的视频学习。JavaScript确实是一门很厉害的语言,学习JS很容易,但是学透却很难。希望大家都可以朝着自己所想的方向去努力。总结中若有错误请指正,非常感谢!!还有就是第一次写文章,语句有些可能不是很通顺,但是有一定基础的人看代码应该就可以了,不仅要看,还得多练,成功不仅仅是天赋,还有努力。加油!!