哈喽大家好,我是阿锋,一个前端小菜鸟。今天给大家带来一个Promise的学习总结。话不多说直接上代码。
前言
首先,我们需要明白。学习一个东西我们得先知道它是什么?为什么需要它?怎么做?也就是著名的三段论。
Promise是什么?
那么我们来想想,Promise是什么??这里我们引用阮一峰大佬ES6中对Promise的解释。如果没看过的,可以去看看。从这里我们可以看出。Promise是一种异步编程解决方案。是一个容器,里面存的是未来某个时间点完成某一件事(一般指网络请求)后给你的东西(一般指网络请求完成后给你返回的数据或者提示,不管是成功还是失败)。
为什么需要Promsie
我们已经知道了Promise是一个什么东西了,那么我们现在来讨论为什么需要它。
这里我们写一段代码,模拟一下以前的网络请求
这是打印的结果
通过代码我们可以看到这种方式有缺点:
- 如果这个请求接口的函数是自己写的:那么你还得去思考成功和失败回调函数的名字。
- 如果这个请求接口的函数不是自己写的:在使用它的时候还得去看别人的源码或者文档,看别人用的哪个名字。 这样下来,我们开发的沟通成本以及效率,代价都比较高。
所以为了提高开发效率降低沟通成本。Promise就出现了。
我们将上面代码用Promise改造一下
打印结果
这里我们可以看到,我们不用去考虑别人使用的回调函数的名字。我们只需要知道,它返回一个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的代码结构
通过打印结果可以看出,当new Promise传入了executor回调函数的时候,executor回调函数立即执行了。
我们用then方法捕获一下resolve回调看看发生了什么。
通过打印,我们可以看到当执行了resolve回调函数的时候,被then方法的第一个回调函数捕获了。同时在调用resolve的时候,Promise的状态变成了fulfilled。同理:执行reject,会被then方法的第二个回调捕获,Promise的状态变成rejected(抛出错误也会被then方法的第二个参数捕获).
同时!!!一旦状态确定了之后就不可以更改了。意味着当我们调用了resolve/reject之中任意一个回调后,再次调用另一个,是不会成功调用的。
resolve的参数
resolve有三种参数可以传,每种参数对应的处理逻辑不一样。
1. 当resolve传的是普通的值或者是对象,那么会直接被then方法的第一个回调函数捕获.
2. 当resolve传的是一个新的Promise,那么新的Promise状态决定旧的Promise的状态。
传入的Promise调用resolve
传入的Promise调用reject
- 当resolve传的是一个实现了thenable的对象(也就是对象有一个then方法。) 传入的对象then方法调用resolve
传入的对象then方法调用reject
then方法
then方法其实是Promise.prototype上的方法。每一个new Promise的实例都可以调用这个方法。他有两个参数且每个参数都是回调函数。第一个参数是Promise实例状态变成fulfilled时回调的函数,第二个参数是Promise的状态变成rejected时回调的函数。(上面已经有打印的结果,可以去看看,主要讲的是后面的)
then方法可以多次调用
then方法执行完了之后是会返回一个新的Promise的。如果有显示的返回。那么返回的这个值会作为一个新Promise调用resolve的参数。有点绕,直接看代码吧
所以Promise才可以链式调用,因为then执行完之后是会返回一个新的Promise的。同时,我们又回到了resolve的参数问题了。这里就不再继续说了。这里值得注意的是,只有抛出错误,才会被then方法的第二个参数捕获。
还有一点需要注意,then方法的第二个回调函数里返回的参数和第一个是一样的,只有在抛出错误的是才会被新Promise的then方法第二个回调函数捕获。
catch方法
catch其实是then方法第二个回调参数的语法糖。因为在实际开发中。我们更习惯这样写
抛出错误也会被catch方法捕获
同理,catch也可以多次调用
catch方法也有返回值,它的返回值状态和then方法的一致
catch方法的捕获有些特殊,它只捕获第一个跑出错误或者第一个调用reject方法。
finally
finally方法是ES9(ES2018)新增的一个方法,它表示无论Promise的状态是fulfilled还是rejected,它都会执行。
前面我们讲到的then、catch、finally方法都是实例方法。都是在Promise.prototype上的。接下来我们来讲一下Promise的类方法
resolve类方法
有时候我们已经有一个结果,但是我们想把它包装成一个Promise,这时候我们就可以用Promise的resolve类方法。
这里又回到了resolve的参数问题上了。所以不再细说了。
reject方法
reject方法和resolve方法是差不多的,不过是将Promise的状态变成了rejected.无论传的是什么值都会变成rejected。
all方法
all方法是将一个或者多个Prmise放在一起,形成一个新的Promise 新的Promise的状态由这些Promise的状态决定
- 当所有的Promise的状态都变成fulfilled时,新的Promise的状态变成fulfilled,并将结果组成一个数组返回
- 当有一个Promise的状态变成了rejected时,新的Promise的状态立即变成rejected,并返回结果。
allSettled
all方法有一个缺陷:就是当有一个Promise的状态变成rejected的时候,其他的Promise的状态就不会有结果了。 为了解决这个问题,ES11就新增了一个api叫allSettled
allSettled方法也是将一个或者多个Promise包裹起来,然后形成一个新的Promise。
- 该方法会在所有的Promise都有结果的时候才会有结果,不论是fulfilled,rejected
- 并且新的Promise的状态都是fulfilled。
通过打印我们可以看到,allSettled方法的结果是一个数组,数组里面是所有Promise的结果的对象,每一个对象里面都有status、value/reason 字段。
race
race翻译成中文就是竞赛的意思。表示谁先有结果新Promise就用谁的结果
any
any方法和race方法是类似的
- any方法会等一个fulfilled状态,新的Promise才会有状态
- 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态;
结束语
以上就是我在看了阮一峰大佬、coderwhy老师的视频的时候个人对Promise的总结。当然,大部分是跟着coderwhy老师的视频学习。JavaScript确实是一门很厉害的语言,学习JS很容易,但是学透却很难。希望大家都可以朝着自己所想的方向去努力。总结中若有错误请指正,非常感谢!!还有就是第一次写文章,语句有些可能不是很通顺,但是有一定基础的人看代码应该就可以了,不仅要看,还得多练,成功不仅仅是天赋,还有努力。加油!!