手写Promise实现
- 一、前言
- 二、代码
- 三、测试
- 四、测试结果
一、前言
阅读参考资料,本文整理出使用 构造函数 手撕出 Promise 的方法,在整理过程中不断添加注解以示思路。有错请指出哟,一起进步!!!class 实现 Promise 请查看参考资料,该作者写得非常好、非常详细!!!
参考资料:promise原理手写实现promise以及async await
二、代码
// 构造函数
function MyPromise(executor) {
// 添加属性
this.PromiseState = 'pending'
this.PromiseResult = null
// 保存实例对象的this
const self = this
// 声明属性
// this.callbacks = {}
this.callbacks = []
function resolve(data){
// 判断状态
// 普通函数的this一般指window对象
// 错误写法:直接this.PromiseState !== 'pending'
if(self.PromiseState !== 'pending')return
// 修改对象状态
self.PromiseState = 'fulfilled'
// 设置对象结果
self.PromiseResult = data
// 调用回调函数
// if(self.callbacks.onFulfilled) {
// onFulfilled(data)
// }
setTimeout(() => {
self.callbacks.forEach(item => {
item.onFulfilled(data)
})
})
}
function reject(reason) {
if(self.PromiseState !== 'pending')return
self.PromiseState = 'rejected'
self.PromiseResult = reason
// js执行顺序:同步任务 > Promise.then() > setTimeout()
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(reason)
})
})
}
try {
// executor是一个函数,resolve函数和reject函数作为参数传递
// 生成Promise实例时就执行
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
// 添加then方法
// then方法返回的是一个Promise对象,方便链式调用
MyPromise.prototype.then = function(onFulfilled, onRejected) {
// 要将实例的this保存下来,普通函数的this指向window对象
const self = this
// 判断回调函数参数
if(typeof onRejected !== 'function') {
onRejected = reason => {
throw reason
}
}
if(typeof onFulfilled !== 'function') {
onFulfilled = data => data
}
return new MyPromise((resolve, reject) => {
// 封装回调函数
function callback(type) {
try {
// 获取回调函数的结果
let result = type(self.PromiseResult)
if(result instanceof MyPromise) {
result.then(data => {
resolve(data)
}, reason => {
reject(reason)
})
} else {
resolve(result)
}
} catch(e) {
reject(e)
}
}
if(this.PromiseState === 'fulfilled') {
callback(onFulfilled)
}
if(this.PromiseState === 'rejected') {
callback(onRejected)
}
if(this.PromiseState === 'pending') {
this.callbacks.push({
onFulfilled: function() {
callback(onFulfilled)
},
onRejected: function() {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
// 1、当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调
// 2、前面任何操作出了异常, 都会传到最后失败的回调中处理
MyPromise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve静态方法
// 静态方法直接绑定到构造函数上,而不是绑定到实例对象上。
// 只能通过构造函数本身调用,实例对象不能调用
MyPromise.resolve = function(data) {
// 返回Promise对象
return new MyPromise((resolve, reject) => {
if(data instanceof MyPromise) {
data.then(data => {
resolve(data)
}, reason => {
reject(reason)
})
} else {
resolve(data)
}
})
}
// 添加reject方法
MyPromise.reject = function(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
// 添加all方法
MyPromise.all = function(promises) {
// promises是n个Promise对象
// 结果返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
return new MyPromise((resolve, reject) => {
let count = 0
let arr = []
for(let i = 0; i < promises.length; i++) {
promises[i].then(data => {
count++
arr[i] = data
// 关键:判断是否所有promises都成功
if(count === promises.length) {
resolve(arr)
}
}, reason => {
reject(reason)
})
}
})
}
// 添加race方法
MyPromise.race = function(promises) {
// 返回一个新的 promise
// 第一个完成的 promise 的结果状态就是最终的结果状态,谁先完成就输出谁(不管是成功还是失败)
return new MyPromise((resolve, reject) => {
for(let i = 0; i < promises.length; i++) {
promises[i].then(data => {
resolve(data)
}, reason => {
reject(reason)
})
}
})
}
三、测试
// Promise链式调用:链式调用意味着你可以在一个Promise完成后,用then方法链式调用另一个Promise。
const p = new MyPromise((resolve, reject) => {
resolve('resolved')
}).then(data => {
return new MyPromise((resolve, reject) => {
resolve('resolved again')
})
}).then(data=>{
console.log(data)
})
console.log('-----------------------------')
const p1 = new MyPromise((resolve, reject) => {
resolve('ok')
})
const p2 = MyPromise.resolve('oh yeah')
const p3 = MyPromise.reject('error')
const p4 = MyPromise.resolve('oh yeah yeah')
const result1 = MyPromise.all([p1, p2, p3])
console.log('all_rejected\n', result1)
console.log('-----------------------------')
const result2 = MyPromise.all([p1, p2, p4])
console.log('all_fulfilled\n',result2)
const result3 = MyPromise.race([p1, p2, p3])
console.log('-----------------------------')
console.log('race\n',result3)