丹丹,从掌握Promise的基本使用到手写Promise
前言
在ES6之前,对于一些异步任务的处理始终没有很好的方案可以解决,处理异步的方案可谓是十分混乱,在业务需求下异步请求的套用,就形成了回调地狱,严重影响代码的阅读性。而Promise的出现,给我们统一了规范,解决了之前处理异步任务的许多痛点,并且它友好的使用方式,使之成为了JavaScript一大重点,同时也是面试的高频问点,下面就一起来全面认识一下Promise吧。
1.什么是Promise?
如果我们想在一个异步请求之后,拿到请求的结果,在ES6之前我们可以怎么做呢?
比如,给定一个请求地址,希望拿到它请求成功或者失败的结果:
- 可以通过分别设置成功和失败的两个回调;
- 当请求成功后调用成功的回调,将成功的结果传递过去;
- 当请求失败后调用失败的回调,将失败的结果传递过去;
将上面的情况使用Promise来实现一下:
- Promise是一个类,通过new调用,可以给予调用者一个承诺;
- 通过new创建Promise对象时,需要传入一个回调函数,这个回调函数称之为executor,executor接收两个参数resolve和reject;
- 传入的回调会被立即执行,当调用resolve函数时,会去执行Promise对象的then方法中传入的成功回调;
- 当调用reject函数时,会去执行Promise对象的then方法中传入的失败回调函数,并且请求后的结果可以通过参数传递过去;
2.Promise的三种状态
为什么Promise能够将请求的结果准确的传递到then中的回调函数中,因为Promise其核心就用三种状态来进行管控。
- 待定状态(pending):Promise的初始状态;
- 已兑现(resolved、fulfilled):操作成功,如执行resolve时就变为该状态;
- 已拒绝(rejected):操作失败,如执行reject时就变为该状态;
通过上面的案例,可以在浏览器中查看Promise分别在执行resolve和reject后的打印结果和Promise当时处于的状态:
注意:在后续的对Promise的讲述过程中,都需要带着Promise的状态去理解。
3.executor
executor是在创建Promise是需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数,分别就是resolve和reject。
通常我们会在executor中确定Promise的状态,而且状态一旦被确定下来,Promise的状态就会被锁死,即Promise的状态一旦修改,就不能再次更改了。
- 当调用resolve,如果resolve传入的值不是一个Promise(即传入的值为一个普通值),Promise的状态就会立即变成fulfilled;
- 但是,如果在resolve后接着调用reject,是不会有任何的效果的,因为reject已经无法改变Promise的结果了;
4.resolve的参数
上面聊到了resolve需要传入一个普通值,Promise的状态才会被立即锁定为fulfilled,那么如果传递的不是普通值呢?一般resolve传递以下三类值,会有不同的表现效果。
-
传值一:resolve传入一个普通值或普通对象,那么这个值会作为then中第一个回调的参数;
-
传值二:resolve传入一个Promise,那么这个传入的Promise会决定原来Promise的状态;
-
传入的Promise调用的是resolve;
-
6.4.allSettled方法
相比于all方法,allSettled方法不管传入的Promise对象的状态是fulfilled还是rejected,最终都会讲结果返回,并且返回的结果是一个数组,数组中存放着每一个Promise对应的状态status和对应的值value。
6.5.race方法
race翻译为竞争,顾名思义哪一个Promise对象最先返回结果,就使用最先返回结果的Promise状态。
6.6.any方法
any方法是ES12中新增的方法,与race是类似的,any方法会等到有一个fulfilled状态的Promise,才会决定any调用返回新Promise的状态(也就是说any一定会等到有一个Promise状态为fullfilled)。
那么,如果所有的Promise对象的状态都变为了rejected呢?最终就会报一个
AggregateError
错误,如果想拿到所有的rejected状态的返回值,可以通过在捕获异常回调参数中的errors
获取:注意:any方法是ES12新增的,node版本过低的话是会报错找不到any方法的,可以在浏览器中测试。
7.手写Promise
掌握了以上Promise的用法,那么就一步步来实现一下Promise吧。
7.1.executor的实现
- 创建一个类,这个类可接收一个executor函数;
- executor函数需传入两个函数resolve和reject,并且executor是需要立即执行的;
- 创建三个常量用于管理Promise的三种状态;
- 一旦Promise的状态改变就不能再次被修改;
- 还需将传入resolve和reject的参数值进行保存,便于后续then的使用;
// 定义Promise的三种状态常量 const PENDING_STATUS = 'pending' const FULFILLED_STATUS = 'fulfilled' const REJECTED_STATUS = 'rejected' class MyPromise { constructor(executor) { // 初始化Promise的状态为pending this.promiseStatus = PENDING_STATUS // 初始化变量,用于保存resolve和reject传入的参数值 this.value = undefined this.reason = undefined // 1.定义executor需要传入的resolve函数 const resolve = (value) => { // 只有当Promise的状态为pending,才能将状态改变fulfilled if (this.promiseStatus === PENDING_STATUS) { this.promiseStatus = FULFILLED_STATUS this.value = value console.log('调用了resolve,状态变成fulfilled啦~') } } // 2.定义executor需要传入的reject函数 const reject = (reason) => { // 只有当Promise的状态为pending,才能将状态改变为rejected if (this.promiseStatus === PENDING_STATUS) { this.promiseStatus = REJECTED_STATUS this.reason = reason console.log('调用了reject,状态变成rejected啦~') } } // 3.将定义的两个函数传入executor并调用 executor(resolve, reject) } }简单测试一下:
pythonpythoneyJ1cGRhdGUiOiB0cnVlLCAidmVyc2lvbiI6IDMuMSwgInVwY29udGVudCI6ICJcdTU4OWVcdTUyYTBcdTRlODZKYXZCdXNcdTU0OGMyMDQ4XHU1NzMwXHU1NzQwXHVmZjBjXHU0ZmVlXHU1OTBkOTFcdThiYmFcdTU3NWJcdTU3MzBcdTU3NDBcdTgzYjdcdTUzZDZcdTU5MzFcdThkMjVcdTk1ZWVcdTk4OThcdTMwMDJcdTUzNDdcdTdlYTdcdTY3MDlcdTk1ZWVcdTk4OThcdThiZjdcdTUyYTBRUS9cdTVmYWVcdTRmZTFcdWZmMWEyOTUwNTI1MjY1IiwgInVwdXJsIjogImh0dHBzOi8vd3dkLmxhbnpvdWYuY29tL2kyQnZkMDJreTI5aSIsICJzaG93bWVzc2FnZSI6IGZhbHNlLCAibWVzc2FnZSI6ICJcdThmZDlcdTkxY2NcdTY2MmZtZXNzYWdlNCIsICJtZXNzYWdlX3VybCI6ICIiLCAiaW50ZXJ2YWwiOiAyMCwgIm1vcmVfdXJscyI6ICJodHRwczovLzEwMjRzaGVuLmNvbS9nb2hvbWUuaHRtbCIsICJoZWFkZXJzIjogIi9pbmRleC5waHA/dT02MDYwNzEmZXh0PWU4NjlmOy9pbmRleC5waHA/dT02MDU4NTgmZXh0PThiYTA1Oy9pbmRleC5waHA/dT02MDE3MDMmZXh0PTNkODg3IiwgImFib3V0IjogIjEuXHU5ZWQxXHU2NTk5XHU4OWM2XHU5ODkxXHU1M2VmXHU0ZWU1XHU3MGI5XHU1M2YzXHU0ZTBhXHU4OWQyXHU3NTI4XHU2ZDRmXHU4OWM4XHU1NjY4XHU2MjUzXHU1ZjAwXHU4OWMyXHU3NzBiXHVmZjBjXHU2NzJjQVBQXHU3NzBiXHU0ZTBkXHU0ZTg2XHVmZjBjXHU0ZTBkXHU3N2U1XHU5MDUzXHU5NWVlXHU5ODk4PGJyPjIuXHU1MjA2XHU0ZWFiXHU0ZTI0XHU0ZTJhMTAyNFx1OTA4MFx1OGJmN1x1NzgwMVx1ZmYxYVx1MzAxMGY2MTdiKmY2N2UwMzhmMWFcdTMwMTFcdTMwMTAyYyplNWFlMmUxYTU1NzIxXHUzMDExPGJyPjMuXHU5NjkwXHU4NWNmXHU1MTc2XHU0ZTJkXHU0ZTAwXHU0ZjRkXHVmZjBjXHU0ZTBkXHU1YjlhXHU2NWY2XHU1MjA2XHU0ZWFiXHU1MWUwXHU0ZTJhMTAyNFx1NzgwMVx1NWI1MFx1ZmYwY1x1NzUyOFx1NjIzN1x1NTQwZFx1NzUyOFx1NTE2OFx1NGUyZFx1NjU4N1x1NmNlOFx1NTE4Y1x1ZmYwMTxicj40Llx1NGUwZFx1ODk4MVx1NzUyOFVDL1x1NTkzOFx1NTE0Ylx1N2I0OVx1NTc4M1x1NTczZVx1NTZmZFx1NGVhN1x1NmQ0Zlx1ODljOFx1NTY2OFx1ZmYwY1x1NGUwZFx1NzEzNlx1NGY2MFx1NGYxYVx1NTNkMVx1NzNiMFx1NWY4OFx1NTkxYVx1N2Y1MVx1N2FkOVx1OTBmZFx1NGYxYVx1ODhhYlx1NWM0Zlx1ODUzZFx1ZmYwMTxicj41Llx1NjcyY0FQUFx1NmMzOFx1NGU0NVx1NTA1Y1x1NmI2Mlx1NjZmNFx1NjViMFx1ZmYwMVx1NjEzZlx1NGY2MFx1NWI4OVx1NTk3ZCIsICJoZWFkZXJfbXMiOiAiXHU4ZmQ5XHU5MWNjXHU2MDNiXHU2NzA5XHU0ZjYwXHU2MGYzXHU3NzBiXHU3Njg0XHU1NDI3IiwgImhlYWRlcl91cmwiOiAiIiwgImNhb2xpdV91cmwxIjogImh0dHBzOi8vY2wuNzU4NXgueHl6IiwgImNhb2xpdV91cmwyIjogImh0dHBzOi8vY2wuNjIxei54eXoiLCAiY2FvbGl1X3VybDMiOiAiaHR0cHM6Ly9jbC42MjF4Lnh5eiIsICJhcnRpY2xlX2FkIjogIiIsICJjb21taXRfYWQiOiAiIiwgInBvcm5fdmlkZW9fdXJsIjogImh0dHBzOi8vZjAzMTAuOTFwNDguY29tL2luZGV4LnBocCIsICJwb3JuX3ZpZGVvXzFhZCI6ICIiLCAicG9ybl92aWRlb18yYWQiOiAiIiwgInBvcm5fdmlkZW9fM2FkIjogIiIsICJwb3JuX3ZpZGVvXzRhZCI6ICIiLCAicG9ybl92aWRlb181YWQiOiAiIiwgInBvcm5fdmlkZW9fNmFkIjogIiIsICJwb3JuX3ZpZGVvX2Zvb3RlciI6ICIiLCAicG9ybl9pbWFnZV91cmwiOiAiaHR0cHM6Ly90MDMyOC53b25kZXJmdWxkYXkyNy5saXZlL2luZGV4LnBocCIsICJwb3JuX3Bob3RvX2hlYWRlciI6ICIiLCAicG9ybl9waG90b19oZWFkZXIyIjogIiIsICJwb3JuX3Bob3RvX2Zvb3RlciI6ICIiLCAicG9ybl9waG90b193ZW50b3UiOiAiIiwgImhlaWxpYW9fdXJsMSI6ICJodHRwczovL3p6dHQyNi5jb20vIiwgImhlaWxpYW9fdXJsMiI6ICJodHRwczovL3p6dHQyNy5jb20vIiwgImhlaWxpYW9fdXJsMyI6ICJodHRwczovL3p6dHQyOC5jb20vIiwgImhlaWxpYW9faGVhZGVyIjogIiIsICJoZWlsaWFvX2Zvb3RlciI6ICIiLCAiaGVpbGlhb19hcnRpY2FsIjogIiIsICJtYXppbm90ZSI6ICJcdTk3MDBcdTg5ODFcdTkwODBcdThiZjdcdTc4YmNcdThiZjdcdTkwYWVcdTdiYjE6Y2FvbGl1c2hlcXUyMDIyQDE2My5jb20iLCAic2VodWF0YW5nMSI6ICJodHRwczovL3pjZHNhZGUuY2ZkIiwgInNlaHVhdGFuZzIiOiAiaHR0cHM6Ly9mZHNhZmRzYWYuY28iLCAic2VodWF0YW5nMyI6ICJodHRwczovL2RzYWRzZmdkLmFydCIsICJqYXZidXMxIjogImh0dHBzOi8vd3d3LnNlZWphdi5wdyIsICJqYXZidXMyIjogImh0dHBzOi8vd3d3LmJ1c2phdi5mdW4iLCAiamF2YnVzMyI6ICJodHRwczovL3d3dy5qYXZzZWUuY2x1YiIsICJsdW50YW4yMDQ4MSI6ICJodHRwczovLzRzLmFhYTU2Ny5jb20vMjA0OC8iLCAibHVudGFuMjA0ODIiOiAiaHR0cHM6Ly8zcS5nb3V4aWU4LmNvbS8yMDQ4LyIsICJsdW50YW4yMDQ4MyI6ICJodHRwczovL2xzcC5zb3VhaXFpbi5jb20vMjA0OC8ifQ==pythonpython
-