前言
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 又加深了一次印象,学习就是不断遗忘的过程,需要我们不断巩固加深记忆,加油伙伴们!