前言
Promise
已经成为前端开发必备技能,它主要解决了异步编程时大量嵌套回调函数,导致的回调低于问题,本篇我将以学习笔记的形式,和大家一起来深入学习它。内容主要包括基本用法和手写两部分,适合刚入门的新手和想深入了解原理的小伙伴。
认识 Promise
CommonJS
社区首先提出了Promise
规范,在ES2015
中被标准化,成为语言规范Promise
是一个对象,用来表示一个异步任务结束之后,是成功了还是失败了,任何一个 Promise 对象的初始状态都为Pending
,当任务成功后,状态改为Fulfilled
,然后执行成功任务的回调onFufilled
;当任务失败后,状态改为Rejected
,然后执行失败任务的回调onRejected
- 状态只能从
Pending
变为Fulfilled
或者从Pending
变成Rejected
,只有这两种变化,而且改变之后将不可能再对其进行修改,就像我承诺,今天晚上要请你吃饭,如果晚上请了,就是 Fulfilled,如果晚上没请,就是 Rejected,假如我说今天要加班,改成明天吧,那也是 Rejected,因为明天的承诺是明天的,今天这个承诺已经有结果了,无法改变了。
Promise 基本用法
第一步:创建实例
Promise
是 ES2015
中新增的一个全局对象,通过 new
创建一个 Promise
实例,传入一个 executor
函数,这个函数会立即开始执行,主要的业务流程都在 executor
函数中
const promise = new Promise((resolve,reject)=>{
if(/*异步操作成功*/){
resolve('执行成功了')
}else{
reject(new Error('执行失败了'))
}
})
复制代码
resolve
和 reject
两个函数作为参数传递给 executor
函数
- 调用
resolve
函数时,将我们的Promise
状态修改为Fulfilled
,并将异步操作成功后的结果作为参数传递出去 - 调用
reject
函数时,将我们的Promise
状态修改为Rejected
,并将异步操作失败的原因作为参数传递出去 - 二者只能调用其一,要么成功,要么失败
- 需要注意的是,
Promise
是用来管理异步的,但它本身不是异步的,executor
函数会立即执行,我们往往会在executor
中编写异步操作
第二步:调用 then 方法
Promise
实例创建好之后,使用它的 then
方法来指定 onFulfilled
或者 onRejected
的回调函数,第一个参数是 onFulfilled
回调,第二个参数是 onRejected
回调,其中 onRejected
可以省略。
promise.then( value =>{
console.log('resolved',value)
}, error =>{ // onRejected 回调可以省略
console.log('rejected',error)
})
复制代码
执行时序
即使我们没有执行任何异步操作,promise.then 中的回调函数,也是在 JS 执行完同步任务之后才去执行:
const promise = new Promise((resolve,reject)=>{
console.log(1)
resolve(100)
console.log(2)
})
promise.then( value =>{
console.log('resolved',value)
}, error =>{
console.log('rejected',error)
})
console.log('3')
/*输出结果*/
// 1
// 2
// 3
// resolved 100
复制代码
new Promise
时先执行 executor
函数,打印出 1 和 2,因为 resolve
是微任务,先不执行它,继续往下执行同步任务,执行 promise.then
,将成功回调和失败回调都存储到起来(存储到 Promie 实例的变量中,后面手写 Promise 的内容会讲到),此时先不执行他们,然后打印出 3,此时同步任务执行完毕,开始执行微任务,调用 then 方法的成功回调,打印出 resolved 100
然后我们再加入定时器来看一下:
const promise = new Promise((resolve,reject)=>{
console.log(1)
resolve(100)
console.log(2)
})
// 在此加入定时器,执行顺序是怎样的呢?
setTimeout(()=>{
console.log('setTimeout')
},0)
promise.then( value =>{
console.log('resolved',value)
}, error =>{
console.log('rejected',error)
})
console.log('3')
/*输出结果*/
// 1
// 2
// 3
// resolved 100
// setTimeout
复制代码
setTimeout
的时间为 0,会立即进入回调队列中排队,等待下一轮的执行。这里有个误区,因为 setTimeout
比 Promise
先执行,我们会以为 setTimeout
会先进入队列中,就先执行,但实际并不是这样。
因为 Promise
属于微任务,setTimeout
属于宏任务,当前同步代码执行完毕后,如果有微任务,就顺带把微任务执行了,如果有宏任务,则等到下一个队列中去执行。关于宏任务和微任务的概念与区别,具体可以参考微任务、宏任务与Event-Loop
微任务是为了提高整体的响应能力,在 JS 中,大部分异步任务都是宏任务,只有 Promise
、MutationObserver
和 node 中的 process.nextTick
会作为微任务执行。
常见的错误
Promise
的本质还是回调,当异步任务结束后,通过 then
方法执行回调,有的同学不自然就会嵌套回调,这是因为对 Promise
用法不清晰,不知道 Promise
链式调用的特点。
promiseA.then(function(value1){
promiseB.then(function(value2){
promiseC.then(function(value3){
/*回调地狱*/
......
})
})
})
复制代码
Promise 的链式调用
then
方法在执行完成后返回一个新的 Promise
对象,因此可以使用链式调用避免回调地狱,使得代码扁平化。
Promise
的链式调用与传统的链式调用有所不同:
- 传统链式调用是在函数中返回
this
Promise
链式调用是在then
中返回一个新的Promise
对象
const promise1 = new Promise((resolve,reject)=>{
resolve(100)
})
const promise2 = promise1.then((value)=>{
console.log(value)
})
const promsie3 = promise2.then((value)=>{
console.log(value)
})
console.log(promise1 === promise2) // false 证明返回的是新 Promise 对象
console.log(promise2 === promise3) // false
复制代码
因为 then
返回的是一个新 Promise
,所以当前调用的 then
,是在给上一个 then
返回的 Promise
对象,添加状态改变后的回调:
const promise = new Promise((resolve,reject)=>{
resolve(100)
})
/*链式调用*/
promise
.then((value)=>{
console.log('11111')
})
.then((value)=>{
console.log('22222')
})
.then((value)=>{
console.log('33333')
})
复制代码
我们可以在 then
方法中手动返回新的 Promise
,也可以返回一个普通值:
promise
.then((value)=>{
// 手动返回新的 Promise
return new Promise((resolve,reject)=>{
resolve(800)
})
})
.then((value)=>{
console.log(value) // 800
// 手动返回普通值
return 'hello promise'
})
.then((value)=>{
console.log(value) // hello promise
})
.then((value)=>{
console.log(value) // undefined 上一个 then 没有返回值
})
复制代码
异常处理
promise
.then(function(value){
console.log(1)
})
.then(function(value){
throw Error('error')
})
.then(function(value){
console.log(2)
})
.catch(function(error){
console.log('onRejected',error)
})
// 输出
// 1
// error
复制代码
- 在链式调用的最后使用
catch
捕获异常,指定失败的回调 - 它捕获到的是整个链式调用中所有的异常,有点类似于 “冒泡”,一直向后传递,直到被
catch
捕获 - 通过这种方式,我们不必在每个
then
中写onRejected
回调,也不必每个then
后面写catch
,这使我们的代码更优雅
静态方法
Promise.resolve( )
如果接收的是普通值,把普通值作为结果,返回一个 Promise
// 返回状态为 Fulfilled 的 Promise 对象
Promise.resolve('hello world')
.then(value=>{
console.log(value) // hello world
})
// 等价于
new Promise((resolve,reject)=>{
resolve('hello world')
})
复制代码
如果接收的是另一个 Promise
对象,则原样返回
const promise = new Promise((resolve,reject)=>{})
const promise2 = Promise.resolve(promise)
console.log(promise === promise2) // true
复制代码
Promise.reject( )
返回一个失败的 Promise,无论传入什么参数,都将作为失败原因
cosnt promise = Promise.reject('hello world')
复制代码
Promise.all( )
将多个 Promise
实例组合成一个新的 Promise
实例,它的成功和失败返回值不同,成功时返回的是一个数组,包含每个 Promise
的执行结果,失败时返回的是最先 reject 的值。
Promise.all
当所有Promise
对象都成功了,才会执行成功回调,只要有一个失败了,就会执行失败回调
const promise = Promise.all([
Promise.resolve({code:200,data:[1,2]}),
Promise.resolve({code:200,data:[3,4]}),
Promise.resolve({code:200,data:[5,6]}),
])
promise.then(function(values){
console.log(values) // 此时拿到的 values 是数组,包含每个 promise 异步任务的执行结果
})
复制代码
比如我们要同时请求多个接口,当所有数据都返回时再执行下一步,这时就可以使用Promise.all
方法
注意:Promise.all
得到的成功结果数组,与调用 Promise.all
时传入的实例顺序相同,也就是上面代码中,请求接口1、请求接口2、请求接口3的顺序,即使请求接口1最后才获取到结果,也是放在最前面。
Promise.allSettled( )
有时我们不关心异步操作的结果,只关心这些操作有没有执行完,于是在 ES2020
中引入了 Promise.allSettled
方法
Promise.allSettled([
Promise.resolve({code:200,data:[1,2]}),
Promise.reject({code:500,errMsg:'服务器异常'}),
Promise.resolve({code:200,data:[3,4]})
])
.then(function(values){
console.log(values)
})
复制代码
Promise.allSettled
与 Promise.all
很相似,唯一不同的是,Promise.allSettled
会拿到每一个 Promise
的状态,无论它是成功或者失败。
Promie.race( )
同样是支持多个 Promise 调用,但与 Promise.all 有所不同,race 是赛跑的意思,Promise.race([p1,p2,p3]) 中哪个执行最快, 就返回哪个结果,无论它是成功还是失败
Promise.all
等待所有任务完成后,新返回的 Promise 才会完成Promise.race
只要有一个任务成功,新返回的 Promise 就会成功,只要有一个 Promise 失败,返回的 Promise 就会失败
Promise.finally( )
ES9
新怎了 finally
方法,无论结果是 Fulfilled
还是 Rejected
,都会执行 finally
指定的回调函数,这样就避免了我们在 then
和 catch
中各写一次操作的情况
// 请求接口时让页面转圈圈
this.loading = true
axios.get('http://juejin.cn/api')
.then(res => {
// this.loading = false
})
.catch(err => {
// this.loading = false
})
.finally(() => {
this.loading = false
})
复制代码
手写 Promise
我们不能直接罗列完整的 Promise
代码,那样看不出思路,我们要从无到有、渐进式地完成这项工作。所以我会在每一步的关键位置写上注释,通过前后代码对比的方式来学习,看似代码很多,但重点在于增量代码。
一个最基本的 Promise
要想手写 Promise
,得先对它的使用方式和特点做下总结:
Promise
通过new
出来,那一定是个构造函数或者类,我们就用类的方式来实现- 接收一个执行器函数
executor
,并且能够立即执行 - 执行器函数接收
resolve
和reject
,它们用于改变Promise
的状态 Promise
有三种状态:Pendding
、Fulfilled
、Rejected
,且一旦确定了就不能改变- 通过
then
方法判断状态,如果是成功则执行onFulfilled
,如果是失败则执行onRejected
// 定义三个状态常量
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
// 接收一个执行器函数 executor
constructor(executor) {
// 立即执行 executor,传入 resolve 和 reject 函数
executor(this.resolve, this.reject)
}
// 每个 Promise 实例都有一个属于自己的状态,初始为 PENDDING
status = PENDDING
// 缓存成功结果和失败原因
value = undefined
reason = undefined
resolve = value => {
/**
* 1.业务代码的异步函数成功后,调用 resolve 并传入成功值 value
* 2.resolve 的作用是将状态改为 FULFILLED,并将 value 保存起来
* 3.为什么是箭头函数:我们是在 executor 中直接调用 resolve 的,如果是普通函数,this 会指向 window,我们需要 this 指向 Promise 实例
* 4.如果状态不是 PENDDING,则不允许修改
*/
if (this.status !== PENDDING) return
this.status = FULFILLED
// 保存成功后的值,将来在 then 方法的成功回调中使用
this.value = value
}
reject = reason => {
// 与 resolve 类似,reject 用于处理异步任务失败的情况
if (this.status !== PENDDING) return
this.status = REJECTED
// 保存失败后的原因,将来在 then 方法的失败回调中使用
this.reason = reason
}
/**
* 1.每个 Promise 实例都有 then 方法,所以将 then 定义在类中
* 2.then 方法接收两个参数,成功回调和失败回调
* 3.根据状态判断调用哪个回调,并传入相应的值
*/
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
// 最后别忘了导出
module.exports = MyPromise
复制代码
测试一下是否可用
const MyPromise = require('./promise.js')
let promise = new MyPromise((resolve, reject) => {
resolve('成功')
})
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
复制代码
处理异步情况
接下来处理下业务中的异步情况,我们在业务代码中加入定时器
const MyPromise = require('./promise.js')
let promise = new MyPromise((resolve, reject) => {
// 异步情况
setTimeout(()=>{
resolve('成功');
},2000)
})
// 主线程不会等待 setTimeout,而是先执行到这里
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
复制代码
主线程不会等待 setTimeout
,往下执行到 then
,但此时还没有执行 resolve
或者 reject
,也就意味着 Promise
的状态还是 PENDDING
,所以要在 then
中加一个判断:如果是 PENDDING
状态,则先将 onFulfilled
和 onRejected
回调函数存储起来,等到异步任务执行完毕,开始执行 resolve
或者 reject
的时候再去调用回调函数
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDDING
value = undefined
reason = undefined
// 缓存成功回调与失败回调
onFulfilled = undefined
onRejected = undefined
resolve = value => {
if (this.status !== PENDDING) return
this.status = FULFILLED
this.value = value
/**
* 针对异步情况,判断成功回调是否存在,如果存在就调用
*/
this.onFulfilled && this.onFulfilled(this.value)
}
reject = reason => {
if (this.status !== PENDDING) return
this.status = REJECTED
this.reason = reason
/**
* 针对异步情况,判断失败回调是否存在,如果存在就调用
*/
this.onRejected && this.onRejected(this.reason)
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else {
/**
* 如果是 PENDDING 状态,表明此时是异步情况
* 但我们还不知道将来是成功还是失败,所以把它们都先存储起来
* */
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
}
module.exports = MyPromise
复制代码
处理多个回调情况
then
方法会被调用多次,每次都会传入成功或失败的回调函数,这些回调都是要执行的,所以要改进一下,将这些函数存储到数组中,在 resolve
和 reject
中依次调用
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDDING
value = undefined
reason = undefined
// 改成用数组存储这些回调
// onFulfilled = undefined
// onRejected = undefined
onFulfilled = []
onRejected = []
resolve = value => {
if (this.status !== PENDDING) return
this.status = FULFILLED
this.value = value
// 由只调用一次,改为遍历数组,调用所有回调函数
// this.onFulfilled && this.onFulfilled(this.value)
while (this.onFulfilled.length) {
this.onFulfilled.shift()(this.value)
}
}
reject = reason => {
if (this.status !== PENDDING) return
this.status = REJECTED
this.reason = reason
// 由只调用一次,改为遍历数组,调用所有回调函数
// this.onRejected && this.onRejected(this.reason)
while (this.onRejected.length) {
this.onRejected.shift()(this.reason)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else {
// 回调可能为多个,全都存储起来
// this.onFulfilled = onFulfilled
// this.onRejected = onRejected
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
}
}
module.exports = MyPromise
复制代码
then 方法的链式调用
then
方法可以链式调用,每次返回的都是Promise
对象- 上一个
then
的返回值,传递给当前then
的回调函数
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDDING
value = undefined
reason = undefined
onFulfilled = []
onRejected = []
resolve = value => {
if (this.status !== PENDDING) return
this.status = FULFILLED
this.value = value
while (this.onFulfilled.length) {
this.onFulfilled.shift()(this.value)
}
}
reject = reason => {
if (this.status !== PENDDING) return
this.status = REJECTED
this.reason = reason
while (this.onRejected.length) {
this.onRejected.shift()(this.reason)
}
}
then(onFulfilled, onRejected) {
/**
* then 方法需要返回一个新的 Promise 实例,实现链式调用
*/
const newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 拿到当前 then 的成功回调函数返回值
let current = onFulfilled(this.value)
/**
* current 可能是 promise 或者普通值,针对不同情况要做不同处理,
* 如果是普通值,直接调用 resolve
* 如果是 promise,查看 promise 的返回结果,再决定调用 resolve 还是 reject
* 我们把处理过程封装成一个函数,方便给 onRejected 同样使用,
* 同时还要对比一下 newPromise 和 current,防止他们是同一个 promise,也就是循环调用的问题
* */
resolvePromise(newPromise, current, resolve, reject)
} else if (this.status === REJECTED) {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
} else {
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
})
return newPromise
}
}
function resolvePromise(newPromise, current, resolve, reject) {
if (current === newPromise) {
return reject(new TypeError('不能循环调用'))
}
if (current instanceof MyPromise) {
current.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(current)
}
}
module.exports = MyPromise
复制代码
细心的同学会发现,newPromise
是在 new Promise
执行完成之后返回的,我们在调用 resolvePromise
时传入的 newPromise
此时还没有获取到,所以我们通过 setTimeout
将其转换成异步代码
then(onFulfilled, onRejected) {
const newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 转为异步代码,是为了获取到 newPromise
setTimeout(() => {
let current = onFulfilled(this.value)
resolvePromise(newPromise, current, resolve, reject)
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
}, 0);
} else {
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
})
return newPromise
}
复制代码
错误处理机制
- 如果执行器函数出错了,应该在
constructor
中捕获出来并抛出 - 如果
onFulfilled
或者onRejected
出错了,也应该捕获并抛出
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
// 捕获执行器函数的错误
try {
executor(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
status = PENDDING
value = undefined
reason = undefined
onFulfilled = []
onRejected = []
resolve = value => {
if (this.status !== PENDDING) return
this.status = FULFILLED
this.value = value
while (this.onFulfilled.length) {
// 不需要传值了
// this.onFulfilled.shift()(this.value)
this.onFulfilled.shift()()
}
}
reject = reason => {
if (this.status !== PENDDING) return
this.status = REJECTED
this.reason = reason
while (this.onRejected.length) {
// 不需要传值了
// this.onRejected.shift()(this.reason)
this.onRejected.shift()()
}
}
then(onFulfilled, onRejected) {
const newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
// 捕获 onFulfilled 的错误
try {
let current = onFulfilled(this.value)
resolvePromise(newPromise, current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
// 捕获 onRejected 的错误
try {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
} else {
// 捕获 onFulfilled 和 onRejected 的错误
// this.onFulfilled.push(onFulfilled)
// this.onRejected.push(onRejected)
this.onFulfilled.push(() => {
setTimeout(() => {
// 捕获 onFulfilled 的错误
try {
let current = onFulfilled(this.value)
resolvePromise(newPromise, current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
})
this.onRejected.push(() => {
setTimeout(() => {
// 捕获 onRejected 的错误
try {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
})
}
})
return newPromise
}
}
function resolvePromise(newPromise, current, resolve, reject) {
if (current === newPromise) {
return reject(new TypeError('不能循环调用'))
}
if (current instanceof MyPromise) {
current.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(current)
}
}
module.exports = MyPromise
复制代码
实现 Promise.all( )
Promise.all
是静态方法,通过static
声明- 接收一个数组,每一项都是一个
Promise
实例或者普通值,遍历这个数组,当所有Promise
执行完毕之后,再返回结果
// Promise.all 是静态方法,通过 static 声明
static all(array) {
let result = [];
//计数器
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index++;
/**
* 因为 for 循环中会存在异步函数,当 for 循环执行完了,异步函数还没有返回结果,此时执行 resolve 会出错
* 所以我们等循环完成之后再执行 resolve
* */
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i++) {
let data = array[i];
if (data instanceof MyPromise) {
// data 是 promise 对象的情况
data.then(value => addData(i, value), reason => reject(reason))
} else {
// data 是普通值的情况
addData(i, data)
}
}
})
}
复制代码
实现 Promise.resolve( ) 和 Promise.reject( )
这两个比较简单,直接撸!
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(err);
})
}
复制代码
如果 finally 的回调函数返回的是一个异步的 promise 对象
实现 catch
如果我们调用 then
方法的时候,没有传递失败回调,那么错误最终会被 catch
捕获
catch (onRejected) {
return this.then(undefined, onRejected)
}
复制代码
完整的代码
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
status = PENDDING
value = undefined
reason = undefined
onFulfilled = []
onRejected = []
resolve = value => {
if (this.status !== PENDDING) return
this.status = FULFILLED
this.value = value
while (this.onFulfilled.length) {
this.onFulfilled.shift()()
}
}
reject = reason => {
if (this.status !== PENDDING) return
this.status = REJECTED
this.reason = reason
while (this.onRejected.length) {
this.onRejected.shift()()
}
}
then(onFulfilled, onRejected) {
const newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let current = onFulfilled(this.value)
resolvePromise(newPromise, current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
} else {
this.onFulfilled.push(() => {
setTimeout(() => {
try {
let current = onFulfilled(this.value)
resolvePromise(newPromise, current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
})
this.onRejected.push(() => {
setTimeout(() => {
try {
let current = onRejected(this.reason)
resolvePromise(current, resolve, reject)
} catch (err) {
reject(err)
}
}, 0);
})
}
})
return newPromise
}
static all(array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index++;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i++) {
let data = array[i];
if (data instanceof MyPromise) {
data.then(value => addData(i, value), reason => reject(reason))
} else {
addData(i, data)
}
}
})
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(err);
})
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
}
function resolvePromise(newPromise, current, resolve, reject) {
if (current === newPromise) {
return reject(new TypeError('不能循环调用'))
}
if (current instanceof MyPromise) {
current.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(current)
}
}
module.exports = MyPromise
复制代码
写在最后
写到这里基本就差不多了,虽然代码中还存在可以优化的点,可以继续打磨,但通过这篇文章的整理,我对 Promise
又加深了一次印象,学习就是不断遗忘的过程,需要我们不断巩固加深记忆,加油伙伴们!