本篇文章将从零手写一个Promise,实现Promise的then , catch 实例方法;和all,allSettled,等静态方法。如有疑问或其他问题欢迎留言指教。
首先我们来实现一个裸的,简易版Promise,请看下文
class MyPromise {
state = 'pending' // 定义promise 的状态 pending | fulfilled | rejected
resolveCallbacks = [] // .then 订阅的方法会放在这里面,等待resolve后执行
constructor(fn) {
// fn 是实例promise 时传入的函数
// resolve 的回调, 传入 value = 1
const resolveHandler = (value) => {
if(this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn())
}
}
// reject 的回调
const rejectHandler = () => {}
// 避免传入的fn运行时候报错,使用try{} catch{} 包裹
try{
fn(resolveHandler, rejectHandler)
}catch(error){
}
}
then(fn) {
// fn 对应p1.then() 里面传入的函数
if(this.state === 'pending') {
// 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
this.resolveCallbacks.push(() => {
// 2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
fn(this.value)
})
}
}
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
p1.then(res => {
console.log(res) // 2s 后,1 就被打印出来了
})
- 简单的实现后会发现有几点问题
- 问题1: .then() 方法传入的是两个函数,传入两个函数该怎么实现呢?
- 问题2: .then 方法只执行了一种状态,=== pending 的时候,那么 等于其他两个状态的时候又是怎样的逻辑呢?
- 问题3: .then() 返回的是一个链式调用,还能继续执行.then 或者 .catch 方法。这样的实现又是怎么的过程?
- 带着这三个问题,我们再来更改一下以上的代码实现
class MyPromise {
// 定义promise 的状态 pending | fulfilled | rejected
state = 'pending'
// 接收resolve 的值
value = undefined
// 接收reject 的值
error = undefined
// .then 订阅的方法会放在这里面,等待resolve后执行
resolveCallbacks = []
// .catch 订阅的方法会放在这里面,等待reject后执行
rejectCallbacks = []
// fn 是实例promise 时传入的函数
constructor(fn) {
// resolve 的回调, 传入 value = 1
const resolveHandler = (value) => {
if(this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn())
}
}
// reject 的回调
const rejectHandler = (e) => {
if(this.state === 'pending') {
this.state = 'reject'
this.error = e
this.rejectCallbacks.forEach(fn => fn())
}
}
// 避免传入的fn运行时候报错,使用try{} catch{} 包裹
try{
fn(resolveHandler, rejectHandler)
}catch(error){
// 函数报错,执行reject
rejectHandler(error)
}
}
// fn, fn2 对应p1.then() 里面传入的函数
then(fn1, fn2) {
// 首先判断fn1 和 fn2 是否是传入的函数
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
if(this.state === 'pending') {
// 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
return new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
// 2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
try {
const res = fn1(this.value)
resolve(res || this.value)
}catch(err) {
console.log(err)
reject(err)
}
})
// reject 存入数据,等待调用
this.rejectCallbacks.push(() => {
try {
const res = fn2(this.error)
reject(res || this.error)
} catch (error) {
reject(error)
}
})
})
}
// 执行的是resolve 的同步状态
if(this.state === 'fulfilled') {
return new MyPromise((resolve, reject) => {
// 处理函数有返回值
try {
const res = fn1(this.error)
reject(res || this.error)
} catch (err) {
reject(err)
}
})
}
// 执行的是reject 的同步状态
if(this.state === 'rejected') {
return new MyPromise((resolve, reject) => {
// 处理函数有返回值
try {
const res = fn2(this.error)
reject(res || this.error)
} catch (err) {
reject(err)
}
})
}
}
// catch 相当于then的语法糖,直接调用.then
catch (fn) {
return this.then(null, fn)
}
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
// 传入两个参数
p1.then(res => {
console.log(res) // 2s 后,1 就被打印出来了
}, err => console.log(err))
const p2 = new MyPromise((resolve, reject) => {
resolve(1)
})
至此,我们上面提出的问题也全部解决,Promise 的 then 和 catch 方法就实现完成了。到这里我们的工作还没有结束,promise 除了能使用new Promise() 调用外还能 Promise.reslove() 来执行函数,这些函数就是Promise上面的静态方法。话不多说,上代码
Promise.resolve()
class MyPromise {
...
static resolve (value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
...
}
- Promise.reject() 同理
Promise.all()
class MyPromise {
...
static all(list) {
const p = new MyPromise((resolve, reject) => {
const res = []
// 遍历里面所有的方法
list.forEach(p => {
p.then(d => {
res.push(d)
if(list.length === res.length) {
resolve(res)
}
}).catch(err => {
// 有一个失败,返回失败
reject(err)
})
})
})
// 返回一个Promise 对象
return p
}
...
}
Promise.allSettled()
...
static allSettled (list) {
const p = new MyPromise((resolve) => {
// 成功和失败的结果都放入数组
let result = []
list.forEach(fn => {
fn.then(res => {
result.push({status: 'fulfilled', value: res})
// 所有方法都返回后,执行resolve
if(result.length === list.length) {
resolve(result)
}
}).catch(err => {
result.push({status: 'rejected', reason: err})
// 所有方法都返回后,执行resolve
if(result.length === list.length) {
resolve(result)
}
})
})
})
return p
}
...
Promise.race()
static race (list) {
const p = new MyPromise((resolve, reject) => {
// 判断是否有promise 已经 返回(不管是错误返回还是正确返回)
let bool = false
list.forEach(fn => {
fn.then(res => {
// 只返回第一次的promise
if(!bool) {
resolve(res)
bool = true
}
}).catch(err => {
// 只返回第一次的promise
if(!bool) {
console.log(err,'err');
resolve(err)
bool = true
}
})
})
})
return p
}
- 完整代码如下
class MyPromise {
// 定义promise 的状态 pending | fulfilled | rejected
state = 'pending'
// 接收resolve 的值
value = undefined
// 接收reject 的值
error = undefined
// .then 订阅的方法会放在这里面,等待resolve后执行
resolveCallbacks = []
// .catch 订阅的方法会放在这里面,等待reject后执行
rejectCallbacks = []
// fn 是实例promise 时传入的函数
constructor(fn) {
// resolve 的回调, 传入 value = 1
const resolveHandler = (value) => {
if(this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn())
}
}
// reject 的回调
const rejectHandler = (e) => {
if(this.state === 'pending') {
this.state = 'reject'
this.error = e
this.rejectCallbacks.forEach(fn => fn())
}
}
// 避免传入的fn运行时候报错,使用try{} catch{} 包裹
try{
fn(resolveHandler, rejectHandler)
}catch(error){
rejectHandler(error)
}
}
// fn, fn2 对应p1.then() 里面传入的函数
then(fn1, fn2) {
// 首先判断fn1 和 fn2 是否是传入的函数
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
if(this.state === 'pending') {
// 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
return new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
// 2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
try {
const res = fn1(this.value)
resolve(res || this.value)
}catch(err) {
console.log(err)
reject(err)
}
})
// reject 存入数据,等待调用
this.rejectCallbacks.push(() => {
try {
const res = fn2(this.error)
reject(res || this.error)
} catch (error) {
reject(error)
}
})
})
}
// 执行的是resolve 的同步状态
if(this.state === 'fulfilled') {
return new MyPromise((resolve, reject) => {
// 处理函数有返回值
try {
const res = fn1(this.error)
reject(res || this.error)
} catch (err) {
reject(err)
}
})
}
// 执行的是reject 的同步状态
if(this.state === 'rejected') {
return new MyPromise((resolve, reject) => {
// 处理函数有返回值
try {
const res = fn2(this.error)
reject(res || this.error)
} catch (err) {
reject(err)
}
})
}
}
// catch 相当于then的语法糖,直接调用.then
catch (fn) {
return this.then(null, fn)
}
// 静态resolve 方法
static resolve (value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
/** all 方法,全部成功就是成功 */
static all(list) {
const p = new MyPromise((resolve, reject) => {
const res = []
// 遍历里面所有的方法
list.forEach(p => {
p.then(d => {
res.push(d)
if(list.length === res.length) {
resolve(res)
}
}).catch(err => {
reject(err)
})
})
})
return p
}
/** allSettled 成功或者失败都会返回 */
static allSettled (list) {
const p = new MyPromise((resolve) => {
let result = []
list.forEach(fn => {
fn.then(res => {
result.push({status: 'fulfilled', value: res})
if(result.length === list.length) {
resolve(result)
}
}).catch(err => {
result.push({status: 'rejected', reason: err})
if(result.length === list.length) {
resolve(result)
}
})
})
})
return p
}
/** race 谁先返回,就直接返回 */
static race (list) {
const p = new MyPromise((resolve, reject) => {
let bool = false
list.forEach(fn => {
fn.then(res => {
if(!bool) {
resolve(res)
bool = true
}
}).catch(err => {
if(!bool) {
console.log(err,'err');
resolve(err)
bool = true
}
})
})
})
return p
}
}