大家好,我是北妈
今天我们来聊聊常见的前端手写功能之Promise\
首先我们来聊聊要实现的功能:
1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行
2、Promise有三种状态,分别为 等待 pending 成功 fulfilled 失败 rejected
pending => fulfilled || pending => rejected
状态一旦确定就不能改变
3、resolve和reject是用来更改状态的
resolve : fulfilled
reject : rejected
4、then方法内部做的事情就是判断状态 如果状态是成功 调用成功的返回函数 如果状态是失败 调用失败的回调函数 then方法是被定义在原型对象中的
5、then成功回调有一个参数,表示成功之后的值,then失败回调有一个参数,表示失败的原因
6、同一个promise对象下面的then方法是可以被调用多次的,then方法是可以链式调用的,后面的then方法回调函数拿到的值是上一个then方法的回调函数的返回值
确定功能后呢,接下来我们就要开始写代码了
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise{
constructor (executor) {
try { // 尝试调用执行器
executor(this.resolve,this.reject)
} catch(e) { // 调用失败
this.reject(e)
}
}
// Promise 状态初始化为等待
status = PENDING;
// 成功之后的值
value = undefined;
// 失败的原因
reason = undefined;
// 成功的回调函数存放的数组
successCallback = [];
// 失败的回调函数存放额数组
failCallback = [];
resolve = value => {
// 如果状态不是等待 阻止程序向下执行
if(this.status !== PENDING) return
// 更改状态为成功
this.status = FULFILLED
// 保存成功之后的值
this.value = value
// 成功回调存在 调用成功回调方法
// this.successCallback && this.successCallback(this.value)
// 因为then是可以多次调用的
// this.successCallback.shift(),截取数组中的第一个元素并返回,会改变原数组
while(this.successCallback.length) this.successCallback.shift()(this.value)
}
reject = reason => {
if(this.status !== PENDING) return
// 更改状态为失败
this.status = REJECTED
// 保存失败的值
this.reason = reason
// 成功回调存在 调用成功回调方法
// this.failCallback && this.failCallback(this.value)
while(this.failCallback.length) this.failCallback.shift()(this.value)
}
then(successCallback, failCallback){
// 当没有成功回调时,将value值往下传递
successCallback = successCallback ? successCallback : value => value;
// 当没有失败回调时,抛出异常
failCallback = failCallback ? failCallback : reason => { throw reason };
// 创建一个新的 Promise对象
let promise2 = new MyPromise((resolve, reject)=>{
// 判断状态
if(this.status === FULFILLED){
setTimeout(()=>{
try {
// 定义 val接收成功回调的返回值
let x = successCallback(this.value);
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
},0)
}else if(this.status === REJECTED){
setTimeout(()=>{
try {
// 定义 val接收成功回调的返回值
let x = failCallback(this.reason)
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
},0)
}else{
// 当异步改变状态时,此时状态为 pending,将成功或失败回调缓存起来
// 每次调用 then方法 ,都会缓存一个回调
this.successCallback.push(() => {
setTimeout(()=>{
try {
// 定义 val接收成功回调的返回值
let x = successCallback(this.value);
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
},0)
})
this.failCallback.push(() => {
setTimeout(()=>{
try {
// 定义 val接收成功回调的返回值
let x = failCallback(this.reason)
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
},0)
})
}
})
// 返回一个 Promise对象
return promise2;
}
catch(failCallback){
return this.then(undefined, failCallback)
}
finally(callback){
// 无论成功或失败都要执行
return this.then(value=>{
return MyPromise.resolve(callback()).then(() => value)
},reason => {
return MyPromise.resolve(callback()).then(() => {throw reason})
})
}
static all(array){
let result = []
let index = 0
// 由index判断是否执行完所有代码,并将数据添加进result中了
return new MyPromise((resolve, reject) => {
// 由addData方法像 result 中添加数据
function addData(key, val){
result[key] = val
index ++
if(index == array.length){
resolve(result)
}
}
array.forEach((item,index) => {
if(item instanceof MyPromise){
item.then(val => addData(index,val),
reason => reject(reason))
}else{
addData(index,item)
}
})
})
}
static resolve(val){
// promise对象直接原样返回
if(val instanceof MyPromise) return val;
// 数值类型将其作为一个新的promise对象的返回值返回
return new MyPromise(resolve => resolve(val))
}
}
function resolvePromise(promise2, x, resolve, reject){
if(promise2 === x){
// console.log('传入了同一个promise');
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
if(x instanceof MyPromise){
// promise对象
// x.then(value => resolve(value), reason => reject(reason))
// 优化为:
x.then(resolve, reject)
}else{
// 普通值
resolve(x)
}
}
| 结语
我是北妈, 一个就怕你们吃亏的互联网型男,我在纷杂的网络和现实世界建立了一个桃花岛,希望和朋友们一起修炼进化,共同提升。欢迎入岛。-->沸点