三分钟带你手写一个完整的Promise
实现一个基础
Promise 是类,接受一个函数参数,然后内部有status 变量和then方法,status状态初始值为pending(等待),then方法的回调函数暂存于内存中,当参数函数的需要提前执行的异步操作执行完之后,执行成功会resolve(value),status变为fulfilled,statu执行失败则会有reject(err),status变为rejected
由以上分析,可以撸出代码:
class MyPromise {
constructor(fn) {
this.status = 'pending'
this.value = null
this.err = null
this.fulfilledCallback = null
this.rejectedCallback = null
const resolve = value => {
this.status = 'fulfilled'
this.value = value
this.fulfilledCallback(value)
}
const reject = err => {
this.status = 'rejected'
this.err = err
this.rejectedCallback(err)
}
try {
fn(resolve, reject)
} catch (err) {
reject(err)
}
}
then(success, fail) {
this.fulfilledCallback = success
this.rejectedCallback = fail
}
}
实现了一个基础Promise的操作,可以进行new MyPromise 传入一个异步函数,然后.then的异步操作
new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log(12)
resolve(34)
})
}).then(rsp => {
console.log(rsp)
})
// 输出 12 34
但是再跟一个.then 就会报错
解决链式操作的报错
但是,这样实现只有一个then函数,真正的Promis后面可以跟很多个then函数,我们可以在此基础上重新写一下then 方法,将this对象返回出来
...
then(success, fail) {
if (this.status === 'fulfilled') {
success(this.value)
}
if (this.status === 'rejected') {
fail(this.err)
}
this.fulfilledCallback = success
this.rejectedCallback = fail
return this
}
将成功事件函数和失败事件函数升级为队列
class MyPromise {
constructor(fn) {
this.status = 'pending'
this.fulfilledCallbacks = []
this.rejectedCallbacks = []
const resolve = value => {
this.fulfilledCallbacks.forEach(cb=>{
cb(value)
})
}
const reject = err => {
this.rejectedCallbacks.forEach(cb=>{
cb(err)
})
}
try {
fn(resolve, reject)
} catch (err) {
reject(err)
}
}
then(success, fail) {
if (this.status === 'fulfilled') {
this.value = success(this.value)
} else if (this.status === 'rejected') {
this.err = fail(this.err)
} else {
this.fulfilledCallbacks.push(success)
this.rejectedCallbacks.push(fail)
}
return this
}
}
new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log(12)
resolve(34)
})
}).then(rsp => {
console.log(rsp)
}).then(rsp => {
console.log(rsp)
})
// 12 34 34
这样下来,我们的所.then里面的回调函数都能够执行
实现下一个then里面的参数函数的实参是上一个的参数函数的返回值
Promise 除了能实现异步,还有完备的链式操作,还能够将上一个上一个then里面参数函数的返回值,作为then里面的参数函数的实参
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
})
}).then(rsp => {
console.log(rsp)
return 2
}).then(rsp => {
console.log(rsp)
})
// 1 2
我们也动手实现一下,我的思路是,在resolve或者rejected之后,将这个forEach循环的函数返回值赋值给this.value,让我们试一下
...
const resolve = value => {
this.value = value
this.fulfilledCallbacks.forEach(cb=>{
this.value = cb(this.value)
})
}
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
})
}).then(rsp => {
console.log(rsp)
return 2
}).then(rsp => {
console.log(rsp)
})
// 1 2
完成
实现Promise.all
话不多说直接上代码
static all(list) {
const results =[]
return new MyPromise((resolve, reject) => {
list.forEach(promise => {
promise.then(rsp => {
results.push(rsp)
if (results.length === list.length) {
resolve(results)
}
})
})
})
}
由上可知,当队列中的promise执行一个就push进入结果队列,当最后一个resolve时候(resolve的最后一个不一定是队列的最后一个);结果也就全部push进去了,(results.length === list.length)来判断,最终返回的是 resolve结果的列表。
let p1 = new MyPromise((resolve)=> resolve(1))
let p2 = new MyPromise((resolve)=> {
setTimeout(()=>{
resolve(2)
}, 1000)
})
let p3 = new MyPromise((resolve)=> {
setTimeout(()=>{
resolve(3)
})
})
MyPromise.all([p1, p2, p3]).then(rsp=> {
console.log(rsp)
})
// [1,3,2]
实现Promise.resolve
Promise.resolve 的实现就相对很简单了
...
static resolve(value) {
return new MyPromise(resolve=>{
resolve(value)
})
}
经过测试也是没有问题的
MyPromise.resolve(1).then(rsp => {
console.log(rsp)
})
// 1
整套代码
整个代码如下:
class MyPromise {
constructor(fn) {
this.status = 'pending'
this.fulfilledCallbacks = []
this.rejectedCallbacks = []
const resolve = value => {
this.status = 'fulfilled'
this.value = value
this.fulfilledCallbacks.forEach(cb=>{
this.value = cb(this.value)
})
}
const reject = err => {
this.status = 'rejected'
this.err = err
this.rejectedCallbacks.forEach(cb=>{
this.value = cb(this.err)
})
}
try {
fn(resolve, reject)
} catch (err) {
reject(err)
}
}
then(success, fail) {
if (this.status === 'fulfilled') {
this.value = success(this.value)
} else if (this.status === 'rejected') {
this.err = fail(this.err)
} else {
this.fulfilledCallbacks.push(success)
this.rejectedCallbacks.push(fail)
}
return this
}
static all(list) {
const results =[]
return new MyPromise((resolve, reject) => {
list.forEach(promise => {
promise.then(rsp => {
results.push(rsp)
if (results.length === list.length) {
resolve(results)
}
})
})
})
}
static resolve(value) {
return new MyPromise(resolve=>{
resolve(value)
})
}
}
总结和讨论
我们也只是写了Promise相对用的多的一些功能,还有一个微任务的模拟没有实现,我们所知,resolve函数执行时候,是有个异步的,实现原理类似于node.js process.nextTick,这个涉及到底层的东西,我们这里就不做讨论
|