Promise 实现
前两节花费了很大的劲总结一下promise 的使用场景,基本用法以及promise A+ 规范解读,通过规范实现以下promise,从代码层面反向在理解一下规范的定义
如何使用
先定义一下如何使用 promise
const promise = new Promise((resolve,reject)=>{
resolve("x")
})
promise.then(res=>{
console.log("结果:", res); // 结果:x
})
开始编码
核心逻辑
- Promise是一个类,使用new Promise 返回一个promise对象, 接受一个
executor
执行器函数, 并且在实例化的时候立即调用执行。 executor
接收两个参数resolve
、reject
, 同时这两个参数也是函数。- Promise 实例具有三种状态, pending,fulFilled, rejected,并且状态改变是单向的,一经改变, 将不能再修改。
- promise 实例 都有
then
方法。then 方法中有两个参数。onResolved
成功回调函数,onRejected
失败回调函数 - 执行器
executor
调用resolve
后, then中onResolved
将会执行, 当执行器executor
调用reject
后, then方法第二个参数onRejected
将会执行。
框架如下
- 构造函数,
new Promise()
会接受一个函数,函数里面有两个参数,分别表示成功和拒绝的回调,此时的状态是 pending
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 拒绝
class PromiseCustom {
// 接受一个处理函数,先完成成功的回调
constructor(executor) {
this.state = PENDING; // 进入状态是 pending
executor(this.triggerResolve.bind(this))
}
// 成功的回调函数
triggerResolve(val) {
// TODO
}
}
- then 方法可以注册多个,也就是成功回调和拒绝回调函数是多个,然后依次调用
constructor(executor) {
// 初始化一个数组,把成功回调push数组中
this.fulfilledList = []
}
triggerResolve(val) {
setTimeout(()=>{
// 判断状态
if(this.state!==PENDING) return
// 改变状态
this.state = FULFILLED;
// 处理回调
this.fulfilledList.forEach(item => item(val))
// 清空数组
this.fulfilledList = []
},0)
}
// 在then方法里面需要把成功的回调push到数组
- then 方法,接受两个参数,
onResolved
成功回调函数,onRejected
失败回调函数。
// 成功的回调函数,该函数是在实例化是注册,在.then 方法使用,所以通过setTimeout处理
triggerResolve(val) {
setTimeout(()=>{
// 判断状态
if(this.state!==PENDING) return
// 改变状态
this.state = FULFILLED;
// 处理回调
},0)
}
// then 方法可以注册多个,所以需要一个递归调用
then(onFulfilled, onRejected) {
const {state} = this
// 实例化下一个promise
const promiseInstance = new PromiseCustom((onNextFulfilled, onNextRejected) => {
// 处理回调
function onFinalFulfilled(val) {
// 判断当前成功回调是否是一个函数,如果不是则忽略(规范2.2)
// 执行下一个then
if (typeof onFulfilled !== 'function') {
onNextFulfilled(val)
} else {
const res = onFulfilled(val)
// 判断是否有.then 方法:
// 如果有使用结果的then方法(规范2.3)
// 如果没有把结果当做下一个then的值
if (res && typeof res.then === 'function') {
res.then(onNextFulfilled)
} else {
onNextFulfilled(res)
}
}
}
// 添加成功回调
if (state===PENDING) this.fulfilledList.push(onFinalFulfilled)
})
// 返回当前实例
return promiseInstance
}
完整代码
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 拒绝
class PromiseCustom {
constructor(executor) {
this.state = PENDING;// 进入状态是 pending
this.fulfilledList = []
executor(this.triggerResolve.bind(this))
}
triggerResolve(val) {
setTimeout(() => {
if (this.state !== PENDING) return
this.state = FULFILLED
this.fulfilledList.forEach(item => item(val))
this.fulfilledList = []
}, 0)
}
then(onFulfilled, onRejected) {
const { state } = this
const promiseInstance = new PromiseCustom((onNextFulfilled, onNextRejected) => {
function onFinalFulfilled(val) {
if (typeof onFulfilled !== 'function') {
onNextFulfilled(val)
} else {
const res = onFulfilled(val)
if (res && typeof res.then === 'function') {
res.then(onNextFulfilled)
} else {
onNextFulfilled(res)
}
}
}
if (state===PENDING) this.fulfilledList.push(onFinalFulfilled)
})
return promiseInstance
}
}
使用自定义的Promise
const promise = new PromiseCustom((resolve, reject) => {
setTimeout(() => {
resolve("XXX")
}, 1000)
})
promise.then(res => {
console.log("结果:", res)
return "X"
}).then(res => {
console.log(res)
})
// 结果: XXX
// X
扩展
添加拒绝状态处理函数
// 1. 添加错误回调数组,并在实例化时候注册拒绝处理函数
constructor(){
this.rejectedList = [];
}
// 2. 添加错误处理函数
triggerReject(val) {
setTimeout(() => {
if (this.state !== PENDING) return;
this.state = REJECTED;
this.rejectedList.forEach(item => item(val))
this.rejectedList = []
}, 0)
}
// 添加处理过程,onFinalFulfilled
function onFinalRejected(val) {
if (typeof onRejected !== 'function') {
onNextRejected(val)
} else {
const res = onRejected(val)
// 只处理 reject 时 return 情况,没有考虑到 throw Error
if (res && typeof res.then === 'function') {
res.then(onNextFulfilled, onNextRejected)
} else {
onNextFulfilled(res)
}
}
}
if (state===PENDING) {
// ...
this.rejectedList.push(onFinalRejected)
}
添加静态方法
- resole & reject
static resole(val) {
return new CustomPromise((resolve, reject) => {
resolve(val)
})
}
static reject(val) {
return new CustomPromise((resolve, reject) => {
reject(val)
})
}
- all
static all(list) {
return new CustomPromise((resolve, reject) => {
let count = 0;
const values = []
for (const [i, customPromiseInstance] of list.entries()) {
customPromiseInstance
.then(
res => {
values[i] = res;
count++;
if (count === list.length) resolve(values)
},
err => {
reject(err)
}
)
}
})
}
Catch 方法
catch(onRejected) {
return this.then(null, onRejected)
}