难点与解决方案:
- promise中包裹了异步任务的处理
- 实例调用then方法时,将then中的回调函数保存起来
- 当promise中的resolve或者reject执行时,执行then办法保存起来的回调函数
- 由于一个实例可以调用多次then方法,而每一个then的回调都要执行,因此存于一个数组中
- then方法的回调返回值也是promise
- then返回的promise实例的状态和值,等同于then的回调返回的promis实例的状态和值
- 异常穿透
- then方法中,如果第二个参数没有值(或者不是函数),则重写该回调,使其为一个函数,并抛出上一个promise失败的结果,实现异常穿透
方式一:使用构造函数封装
```javascript // 定义构造函数 function Promise(executor) { this.PromiseState = ‘pending’ // 记录状态 this.PromiseResult = undefined // 记录返回值 this.callbacks = [] // 存放then的回调函数,处理异步事件,使用数组可存多个then的回调函数 // 定义resolve函数 function resolve(data) { if (this.PromiseState !== ‘pending’) return // 如果状态已经改变,则不执行下面的代码 this.PromiseState = ‘fulfilled’ // 改变状态 this.PromiseResult = data // 存入结果值 // 异步执行,调用then中的回调函数 this.callbacks.forEach(item => { if (item.onResolve) item.onResolve(data) // 执行then中的成功回调 }); } // 定义reject函数 function reject(data) { if (this.PromiseState !== ‘pending’) return this.PromiseState = ‘rejected’ this.PromiseResult = data // 异步执行,调用then中的回调函数 this.callbacks.forEach(item => { if (item.onReject) item.onReject(data) }); } try { // 执行new promise传入的回调 executor(resolve.bind(this), reject.bind(this)) } catch (err) { reject.call(this, err) // 记录失败原因,并改变状态 } }
- then方法中,如果第二个参数没有值(或者不是函数),则重写该回调,使其为一个函数,并抛出上一个promise失败的结果,实现异常穿透
// 定义then方法
Promise.prototype.then = function (onResolve, onReject) {
// 保存this
let self = this
// 判断then传入的回调是不是函数,实现异常穿透
if (typeof onReject !== “function”) onReject = err => { throw err }
if (typeof onResolve !== “function”) onResolve = res => res
// then方法返回一个promise
return new Promise((resolve, reject) => { // 使用箭头函数this指向调用then的Promise
// 声明一个函数,用来改变then返回的promise的状态,type为then的第几个参数
let callback = function (type) {
try {
let res = type(self.PromiseResult)
// 如果then的回调函数返回了一个promise
// 那then返回的promise的状态和值就等于这个promise的状态和值
if (res instanceof Promise) {
res.then(r => {
resolve(r) // 改变状态为成功,并记录返回的结果
}, e => {
reject(e) // 改变状态为失败,并记录返回的结果
})
} else { // 回调返回的不是promise
resolve(res)
}
} catch (err) { // 回调函数抛错
reject(err) // 改变状态为失败
}
}
// 如果promise的状态已经成功
if (this.PromiseState === ‘fulfilled’) {
callback(onResolve)
// 如果promise状态是失败
} else if (this.PromiseState === ‘rejected’) {
callback(onReject)
} else { // 如果promise的状态是pending,也就是promise中有异步任务
// 有多个回调都要保存,所以存在一个数组中
this.callbacks.push({
onResolve: function () {
callback(onResolve)
},
onReject: function () {
callback(onReject)
}
})
}
})
}
// 定义catch方法,调用then的异常处理方法即可 Promise.prototype.catch = function (onReject) { return this.then(undefined, onReject) }
<a name="loVx3"></a>
## 方式二:class定义类
> 思路与构造函数封装promise一致
```javascript
class Promise {
constructor(executor) {
this.PromiseState = 'pending' // 记录状态
this.PromiseResult = undefined // 记录返回值
this.callbacks = [] // 记录then的回调
// 执行promise的传入的回调函数
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.call(this, error)
}
}
resolve(data) {
if (this.PromiseState !== "pending") return
this.PromiseState = 'fulfilled'
this.PromiseResult = data
// 异步执行,调用then中的回调函数
this.callbacks.forEach(item => {
item.onResolve(data)
})
}
reject(data) {
if (this.PromiseState !== "pending") return
this.PromiseState = 'rejected'
this.PromiseResult = data
this.callbacks.forEach(item => {
item.onReject(data)
})
}
// 定义promise的then方法
then(onResolve, onReject) {
let self = this
// 处理异常穿透
if(typeof onResolve !== 'function') onResolve=res=>res
if(typeof onReject !== 'function') onReject=err=>{throw err}
// then方法返回一个promis实例
return new Promise((resolve, reject) => {
// 处理then的参数的返回值
function resultThen(type) {
try {
let res = type(self.PromiseResult) // 执行then的回调函数,并获取返回值
if (res instanceof Promise) { // then的回调的返回值如果是promise
res.then(r => {
resolve(r)
}, e => {
reject(e)
})
} else {
resolve(res)
}
} catch (error) {
reject(error)
}
}
// 判断promise实例的状态,并做对应处理
if (this.PromiseState === 'fulfilled') {
resultThen(onResolve)
} else if (this.PromiseState === 'rejected') {
resultThen(onReject)
} else { // promise是pending状态
this.callbacks.push({ // 将then的回调保存起来
onResolve: function () {
resultThen(onResolve)
},
onReject: function () {
resultThen(onReject)
}
})
}
})
}
// 定义promise的catch方法,等同于调用的then方法传入第二个参数
catch(onReject){
return this.then(undefined,onReject)
}
}