引用资料
- 前端开发核心知识进阶-你以为我真的想让你手写 Promise 吗,其实基本上都是看这个文章之后写的,如果想更好理解可以看大佬的文章;
要实现的API
Promise 解释
- Promise 大部分的方法都会返回一个Promise对象,因为我们要做链式调用;
- 调用then,catch等方法时,可能会出现三种状态,fulfilled,rejected,pending,前面两种相对容易理解,pending的话则需要使用数组来保存回调方法,并在resolve/reject时清空数组里面的回调列表;
- then/catch方法传入的参数都是一个回调方法,回调方法返回的数据会在返回的Promise对象中的result/error属性中;
Promise 构造方法
Promise 构造方法使用例子
let p = new Promise((resolve,reject)=>{
resolve('result');
// 或者 reject('error');
})
所以Promise 构造方法肯定是接收一个方法,我们可以根据其特性反推出其构造方法
class Promise{
// onFulfilledArray 和 onRejectArray 两个数组的意义就是处理异步逻辑
// 打个比方,假设在reject 之前,通过.then 绑定几个方法,就会写入两个数组中了.
private onFulfilledArray : Function[] = [];
private onRejectedArray : Function[] = [];
status : PROMISE_STATUS = PROMISE_STATUS.PENDING;
result : any = null;
error : any = null;
constructor(apply: Function){
const onFulfill = (result)=>{
if(this.status === PROMISE_STATUS.PENDING){
this.status = PROMISE_STATUS.FULFIL;
this.result = result;
// resolve时把onFulfilledArray中绑定的方法全部执行了
this.onFulfilledArray.forEach(fun=>{
fun(result);
})
}
},
onReject = (error)=>{
if(this.status === PROMISE_STATUS.PENDING){
this.status = PROMISE_STATUS.REJECT;
this.error = error;
// reject 把数组里面的方法全部执行了
this.onRejectedArray.forEach(fun=>{
fun(error);
})
}
}
apply(onFulfill,onReject);
}
}
这一部分是最比较的简单,只需要有逆向思维,基本上能明白了;
then 方法的实现
Primise.then 方法接收两个参数,分别是resolve回调方法和reject回调方法,只会执行其中一个方法,then 方法是整个Promise的核心部分,最难理解的部分也是在这里。 then方法接收两个入参,都是回调,一个是resolve,一个是reject方法,根据Promise.status有三种情况:
- status === 'Fulfiled' 时,直接调用resolve回调方法,并把回调方法返回结果生成一个新的Promise,返回;
- status === 'Rejected' 时,直接调用reject回调方法,并把回调返回结果生成一个新的Pomise,返回;
- status === 'Pending'时,我们需要等待Promise的结果,但是因为我们需要返回一个Promise的原因,所以才有了把push 进onFulfilledArray,onRejectedArray数组的这种操作;
// 后面会解释resolvePromise方法的用处;
resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){
}
then(onFulfilled : Function, onRejected : Function) : Promise {
// 如果没有传入,则补充默认的onFulfilled/onRejected方法
onFulfilled = onFulfilled ? onFulfilled : data => data;
onRejected = onRejected ? onRejected : error => error;
let promise2 : Promise;
// 如果调用时Promise状态是完成了的
if(this.status === PROMISE_STATUS.FULFIL){
// 返回一个新的Promise对象
return promise2 = new Promise((resolve,reject)=>{
try{
let result = onFulfilled(this.result);
// 这里是一个封装了的处理result的方法
// 可以处理 result 是 Promise对象、或者其它数据
this.resolvePromise(promise2,result,resolve,reject);
}catch(e){
reject(e);
}
})
}
// 如果调用时Promise状态是rejected
if(this.status === PROMISE_STATUS.REJECT){
return promise2 = new Promise((resolve,reject)=>{
try{
let result = onRejected(this.error);
this.resolvePromise(promise2,result,resolve,reject);
}catch(e){
reject(e);
}
})
}
// 如果调用时Promise状态是Pending时,则需要把回调放进onFulfilledArray/onRejectedArray数组中,让Promise resolve/reject时执行数组里面的方法
if(this.status === PROMISE_STATUS.PENDING){
return promise2 = new Promise((resolve,reject)=>{
this.onFulfilledArray.push(result=>{
try{
let _result = onFulfilled(result);
this.resolvePromise(promise2, _result, resolve, reject);
}catch(e){
reject(e)
}
})
this.onRejectedArray.push(result=>{
try{
let _result = onRejected(result);
this.resolvePromise(promise2, _result, resolve, reject);
}catch(e){
reject(e)
}
})
})
}
return this;
}
resolvePromise 方法
resolvePromise 方法是我们封装来处理新生成的Promise 与回调返回结果相关result 或者error的逻辑; result 可能有以下几种情况:
- Promise来的,在Promise.then的结果处理;
- 直接处理;
resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){
if(promise2 === result){
return reject('error');
}
if(result instanceof Promise){
if(result.status === PROMISE_STATUS.PENDING){
result.then(value=>{
this.resolvePromise(promise2,value,resolve,reject);
}, reject)
}else{
result.then(resolve,reject);
}
return;
}
resolve(result);
}
Promise.catch
catch(onReject: Function) : Promise {
if(this.status === PROMISE_STATUS.FULFIL){
return this;
}
let promise2;
return promise2 = new Promise((resolve,reject)=>{
if(this.status === PROMISE_STATUS.REJECT){
let result = onReject(this.error);
this.resolvePromise(proimse2,result,resolve,reject);
return;
}
this.then((result)=>{
this.resolvePromise(promise2,result,resolve,reject);
},(error)=>{
this.resolvePromise(promise2,onReject(error),resolve,reject);
})
})
}
Promise.reject
static reject(error){
return new Promise((resolve,reject)=>{
reject(error);
});
}
Promise.resolve
static resolve(result){
return new Promise((resolve,reject)=>{
resolve(result);
});
}
Promise.all
static all(promises: Promise[]): Promise{
let resultArray = new Array(promises.length);
return new Promise((resolve,reject)=>{
let n = 0, maxLength = resultArray.length;
let setResult = function(item,idx){
if(idx + 1 > maxLength) reject('cao');
if(!resultArray[idx]){
n ++;
resultArray[idx] = item;
if(n == maxLength ){
resolve(resultArray);
}
}
}
for(let idx =0; idx < promises.length; idx ++ ){
let item = promises[idx];
try{
if(item instanceof Promise){
item.then((result)=>{
setResult(result,idx);
}, (error)=>{
reject(error);
})
}else{
setResult(promises[idx],idx);
}
}catch(e){
reject(e);
}
}
})
}
Promise.race
static race(promises : Promise[]) : Promise{
return new Promise((resolve,reject)=>{
let flag = false;
promises.forEach(p => {
if(flag){ return; }
if(p instanceof Promise){
return p.then(result=>{
if(flag){ return; }
flag = true;
resolve(result);
},error=>{
if(flag){ return; }
flag = true;
reject(error);
})
}
flag = true;
resolve(p);
})
})
}
全部代码Promise
enum PROMISE_STATUS {
PENDING,
FULFIL,
REJECT,
}
class Promise{
private onFulfilledArray : Function[] = [];
private onRejectedArray : Function[] = [];
status : PROMISE_STATUS = PROMISE_STATUS.PENDING;
result : any = null;
error : any = null;
constructor(apply: Function){
const onFulfill = (result)=>{
if(this.status === PROMISE_STATUS.PENDING){
this.status = PROMISE_STATUS.FULFIL;
this.result = result;
this.onFulfilledArray.forEach(fun=>{
fun(result);
})
}
},
onReject = (error)=>{
if(this.status === PROMISE_STATUS.PENDING){
this.status = PROMISE_STATUS.REJECT;
this.error = error;
this.onRejectedArray.forEach(fun=>{
fun(error);
})
}
}
apply(onFulfill,onReject);
}
resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){
if(promise2 === result){
return reject('error');
}
if(result instanceof Promise){
if(result.status === PROMISE_STATUS.PENDING){
result.then(value=>{
this.resolvePromise(promise2,value,resolve,reject);
}, reject)
}else{
result.then(resolve,reject);
}
return;
}
resolve(result);
}
then(onFulfilled : Function, onRejected : Function) : Promise {
onFulfilled = onFulfilled ? onFulfilled : data => data;
onRejected = onRejected ? onRejected : error => error;
let promise2 : Promise;
if(this.status === PROMISE_STATUS.FULFIL){
return promise2 = new Promise((resolve,reject)=>{
try{
let result = onFulfilled(this.result);
this.resolvePromise(promise2,result,resolve,reject);
}catch(e){
reject(e);
}
})
}
if(this.status === PROMISE_STATUS.REJECT){
return promise2 = new Promise((resolve,reject)=>{
try{
let result = onRejected(this.error);
this.resolvePromise(promise2,result,resolve,reject);
}catch(e){
reject(e);
}
})
}
if(this.status === PROMISE_STATUS.PENDING){
return promise2 = new Promise((resolve,reject)=>{
this.onFulfilledArray.push(result=>{
try{
let _result = onFulfilled(result);
this.resolvePromise(promise2, _result, resolve, reject);
}catch(e){
reject(e)
}
})
this.onRejectedArray.push(result=>{
try{
let _result = onRejected(result);
this.resolvePromise(promise2, _result, resolve, reject);
}catch(e){
reject(e)
}
})
})
}
return this;
}
catch(onReject: Function) : Promise {
if(this.status === PROMISE_STATUS.FULFIL){
return this;
}
let promise2;
return promise2 = new Promise((resolve,reject)=>{
if(this.status === PROMISE_STATUS.REJECT){
let result = onReject(this.error);
this.resolvePromise(proimse2,result,resolve,reject);
return;
}
this.then((result)=>{
this.resolvePromise(promise2,result,resolve,reject);
},(error)=>{
this.resolvePromise(promise2,onReject(error),resolve,reject);
})
})
}
static reject(error){
return new Promise((resolve,reject)=>{
reject(error);
});
}
static resolve(result){
return new Promise((resolve,reject)=>{
resolve(result);
});
}
static all(promises: Promise[]): Promise{
let resultArray = new Array(promises.length);
return new Promise((resolve,reject)=>{
let n = 0, maxLength = resultArray.length;
let setResult = function(item,idx){
if(idx + 1 > maxLength) reject('cao');
if(!resultArray[idx]){
n ++;
resultArray[idx] = item;
if(n == maxLength ){
resolve(resultArray);
}
}
}
for(let idx =0; idx < promises.length; idx ++ ){
let item = promises[idx];
try{
if(item instanceof Promise){
item.then((result)=>{
setResult(result,idx);
}, (error)=>{
reject(error);
})
}else{
setResult(promises[idx],idx);
}
}catch(e){
reject(e);
}
}
})
}
static race(promises : Promise[]) : Promise{
return new Promise((resolve,reject)=>{
let flag = false;
promises.forEach(p => {
if(flag){ return; }
if(p instanceof Promise){
return p.then(result=>{
if(flag){ return; }
flag = true;
resolve(result);
},error=>{
if(flag){ return; }
flag = true;
reject(error);
})
}
flag = true;
resolve(p);
})
})
}
}