Promise主要为了解决回调函数在js中使用的缺点而诞生的,比如现在实现一个串行任务,这个串行任务包括三个任务,如果用回调来实现就会造成地域回调。
手写Promise来模拟实现原生Promise的效果其实不难,重点在于弄清楚Promise的三个状态,以及三个状态对应的操作, 主要要搞清楚then函数的逻辑, promise只有状态改变之后才会执行then方法,并且then方法返回一个新的promise, 并且then中的方法是异步执行的,当Promise异步resolve时,要把then中的两个回调函数添加到callback数组中,在promise resolve的时候再去数组中取出调用即可,还有一点需要注意,即resolveFn这个回调函数也需要异步执行
。
本示例中的异步均使用 setTimeout来模拟,实际实现中应该不是用的setTimeout,这样会造成性能瓶颈。
下边使用ES6面向对象的方法来实现一版, 具体函数都有注释,这里为了便于理解,有些耦合性高的地方没有处理,实际上可以把try/catch 提取一下解耦,这里的代码是参考B站上一个教程写的,那个老师(后盾人)讲的深入浅出,比较适合新手理解。如果有遇到不理解的,可以debug一下,基本上就没有什么问题了
class MyPromise {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
//构造函数
constructor(executor) {
this.status = MyPromise.PENDING
this.data = null
//把回调函数以对象形式放到数组中,只需要定义一个数组即可
this.callback = []
//this.resolve = this.resolve.bind(this)
//executor函数执行可能出错
try{
//this绑定
executor(this.resolve.bind(this), this.reject.bind(this))
}catch(e) {
//如果executor函数出错,则promise的状态为rejected
this.reject(e)
}
}
//js面向对象方法之间不能加逗号分隔,同时方法不需要添加 function 关键字
resolve(value) {
if(this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED
this.data = value
//resolve的时候处理回调, 回调函数也要异步执行
for(let fn of this.callback) {
setTimeout(() => {
fn.resolvedFncb(value)
})
}
}
}
//类方法reject
reject(reason) {
if(this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED
this.data = reason
//reject的时候处理回调, 回调函数也要异步执行
for(let fn of this.callback) {
setTimeout(() => {
fn.rejectedFncb(reason)
})
}
}
}
//then定义为返回一个新的MyPromise
then(resolvedFn, rejectedFn) {
//console.log(resolvedFn)
resolvedFn = typeof resolvedFn === 'function' ? resolvedFn : function(v){return v}
rejectedFn = typeof rejectedFn === 'function' ? rejectedFn : function(v){throw v}
let p = new MyPromise((resolve, reject) => {
//console.log('我在这')
//此处this 为第一次new 的 Promise
//console.log(this)
if(this.status === MyPromise.FULFILLED) {
//调试时为何一下从setTimeout跳到了 this.status === MyPromise.PENDING
//猜测是运行了另一个then,打断点测试看看,是的,因为resolve那里是异步的
setTimeout(() => {
try{
let x = resolvedFn(this.data)
if(p === x) {
throw new TypeError('Chaining cycle detected for promise')
}
if(x instanceof MyPromise) {
//这样写值如何传递过去?
//其实这样写,resolve/reject 函数肯定会被调用, 这时 resolvedFn ==> resolve
//然后绕一圈会再到 let x = resolvedFn(this.data) ==> let x = resolve(this.data) <--->跟 resolve(res) 效果是一样的
//比较巧妙
x.then(resolve, reject)
//这样写就知道了
// x.then(res => {
// resolve(res)
// }, err => {
// reject(err)
// })
//console.log(x)
}else{
resolve(x)
}
}catch(e) {
rejectedFn(e)
}
})
}
if(this.status === MyPromise.REJECTED) {
setTimeout(() => {
try{
let x = rejectedFn(this.data)
if(p === x) {
throw new TypeError('Chaining cycle detected for promise')
}
if(x instanceof MyPromise) {
x.then(resolve, reject)
}else{
resolve(x)
}
}catch(e) {
rejectedFn(e)
}
})
}
if(this.status === MyPromise.PENDING) {
//console.log('我在这')
this.callback.push({
resolvedFncb: (value) => {
try{
let x = resolvedFn(value)
if(p === x) {
throw new TypeError('Chaining cycle detected for promise')
}
if(x instanceof MyPromise) {
x.then(resolve, reject)
}else{
resolve(x)
}
}catch(e) {
rejectedFn(e)
}
},
rejectedFncb: (reason) => {
try{
let x = rejectedFn(reason)
if(p === x) {
throw new TypeError('Chaining cycle detected for promise')
}
if(x instanceof MyPromise) {
x.then(resolve, reject)
}else{
resolve(x)
}
}catch(e) {
rejectedFn(e)
}
}
})
//this.callback.push(resolvedFn)
}
})
return p
}
//静态resolve方法, MyPromise.resolve()返回一个MyPromise
static resolve(value) {
return new MyPromise((resolve, reject) => {
if(value instanceof MyPromise) {
//写法一,容易理解
value.then(res => {
resolve(res)
}, err => {
reject(err)
})
}else{
resolve(value)
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
if(reason instanceof MyPromise) {
//写法二,不太容易理解
reason.then(resolve, reject)
}else{
reject(reason)
}
})
}
//这里的实现不能按照添加顺序返回结果
static all(promises) {
let result = []
return new MyPromise((resolve, reject) => {
//promises中有一个reject,则reject
//promises所有resolve, 则返回[res1, res2, res3]
// for(let p of promises) {
// if(p.status === MyPromise.REJECTED){
// reject()
// }else{
// p.then(res => {
// result.push(res)
// resolve()
// })
// }
// }
for(let p of promises) {
p.then(res => {
result.push(res)
if(result.length === promises.length) {
resolve(result)
}
}, err => {
reject(err)
//throw new Error('Uncaught (in promise) ' + err)
})
}
})
//return
}
static race(promises) {
return new MyPromise((resolve, reject) => {
//for循环里的逻辑是同步的
for(let p of promises) {
p.then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
}
参考:
本文由 dealdot <dealdot#163.com> 创作, Full Stack Developer @ DeepBlue
本文最后编辑时间为: Aug 30, 2021 at 11:43 am
转载请注明来源