手写Promise太难?那是你不会拆分需求!
现在面试也越来越
内卷
了,动不动就手写各种源码;笔者前几天面试就被问到Prmoise的实现原理。当然手写源码不是目的,可能就是为了考察对知识的掌握程度。很多人一听到手写Promise
就头大,毫无思路,其实我们把Promise
功能需求拆封一下,分步骤实现;写起来就相对简单了,并且易于理解,下面就带大家手写一个Promise
。
阅读小提示:本文看起来篇幅很长,因为每部分都贴出了完整代码,所以代码量比较大。每个步骤新增/修改
的代码部分都会标明步骤和思路,跟着步骤阅读即可。耐心看完,相信会有收获!如果现在没时间阅读,建议点个关注
或收藏
。
Promise基本逻辑实现
- 先贴代码,分析一下:
new Promise((resolve,reject)=>{
console.log('LonJIn带你手写Promise');
resolve('hello')
}).then((res)=>{
console.log(res)
})
核心逻辑分析
-
首先,我们看到
Promise
前面调用了new
,说明Promise
是一个类 -
它有三种状态:
等待(pending)
、成功(fulfilled)
、失败(rejected)
,状态一旦从pending
变成fulfilled
或rejected
就不可更改 -
在
new Promise
中传入了一个函数,我们可以把它称之为执行器,执行器会立即执行 -
在执行器中传入了
resolve
和reject
,用来改变它的状态 -
then
方法内部做的事情就是判断状态,如果状态是成功,调用成功回调函数,如果状态是失败,就调用失败回调函数,且then
方法会接收一个成功或者失败的值。
代码实现
- 我们先建立一个
MyPromise.js
文件,在这个文件中编写我们的Promise。
//定义三个常量
const PENDING='pending', //等待
FULFILLED='fulfilled', //成功
REJECTED='rejected'; //失败
class MyPromise{
constructor(exector){
// 立即执行函数,传入resolve方法和reject方法
exector(this.resolve,this.reject)
};
//定义一个初始状态
status=PENDING;
//保存成功后的值
value=undefined;
//保存失败后的值
reason=undefined;
//成功
resolve=value=>{
//判断当前状态是否为PENDING,如果不是就return
if(this.status!==PENDING)return;
//更改状态为fulfilled
this.status=FULFILLED;
//保存成功的返回值
this.value=value;
};
//失败
reject=reason=>{
//判断当前状态是否为PENDING,如果不是就return
if(this.status!==PENDING)return;
//更改状态为rejected
this.status=REJECTED;
//保存失败的返回值
this.reason=reason;
};
//then方法会接收两个回调函数,分别为成功和失败的回调函数
then(successCallback,failCallback){
//判断当前状态,然后调用相应的函数
if(this.status===FULFILLED){
//传入返回值
successCallback(this.value)
}else if(this.status===REJECTED){
//传入返回值
failCallback(this.reason)
}
}
}
//导出MyPromise
module.exports = MyPromise
- 我们上面分析的基本完成,新建一个
index.js
导入测试一下:
//index.js
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
console.log('lonjin');
resolve(200)
// reject('erro')
})
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
//lonjin
//200
- 调用之后可以正常输出,说明之前写的没有问题,但还有个问题:我们没有考虑异步的时候该怎么办?比如下面的代码:
//index.js
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
//由于setTimeout为异步代码,then会马上执行,但此时状态还为pending之前并没有判断等待这个状态
setTimeout(() => {
resolve(200)
}, 100);
})
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
处理异步调用
- 由于执行器可能有异步代码,所以我们在
then
方法中还需要判断一下状态,然后做相应的处理
代码如下(为了思路清晰,只对做更改的地方加注释,会标注实现步骤,按步骤阅读即可):
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
exector(this.resolve,this.reject)
};
status=PENDING;
value=undefined;
reason=undefined;
//定义一个成功回调函数
successCallback=undefined;
//定义一个失败回调函数
failCallback=undefined;
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
/* 步骤2
-------------------------------------------------
判断成功回调是否存在,如果存在,直接调用
*/
this.successCallback && this.successCallback(this.value)
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
/* 步骤3
-------------------------------------------------
判断失败回调是否存在,如果存在,直接调用
*/
this.failCallback && this.failCallback(this.reason)
};
then(successCallback,failCallback){
if(this.status===FULFILLED){
successCallback(this.value)
}else if(this.status===REJECTED){
failCallback(this.reason)
}else{
/* 步骤1
-------------------------------------------------
等待状态,处理异步逻辑
由于不知道状态,所以我们需要把成功和失败的回调函数先保存起来
保存回调函数 */
this.successCallback=successCallback;
this.failCallback=failCallback;
}
}
}
//导出MyPromise
module.exports = MyPromise
- 验证代码:
//index.js
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
//由于setTimeout为异步代码,then会马上执行,但此时状态还为pending之前并没有判断等待这个状态
setTimeout(() => {
resolve(200)
}, 100);
})
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
- 我们可以看到代码可以正常输出,异步就算处理完成。
实现then()多次调用
Promise
的then
方法是可以被多次调用的。如果是同步回调,那么直接返回当前的值就行;如果是异步回调,那么保存的成功失败的回调,需要用不同的值保存,因为都互不相同。所以之前的代码需要改造一下。
//index.js
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve(200)
}, 100);
})
//多次调用的情况 目前只会输出一次
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
n.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
代码实现
- 为了解决多次调用的情况,之前我们定义了一个
successCallback
回调函数,默认为undefined
,这时候我们需要把它改成数组形式,在resolve
或reject
回调函数中取数组最后一个保存的回调执行即可
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
exector(this.resolve,this.reject)
};
status=PENDING;
value=undefined;
reason=undefined;
/* 步骤1
-------------------------------------
将successCallback和failCallback改成数组
*/
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
/* 步骤3
-------------------------------------
判断successCallback数组中是否有值,有值的话就取数组最后的执行
*/
while(this.successCallback.length)this.successCallback.shift()(this.value)
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
/* 步骤4
-------------------------------------
判断failCallback数组中是否有值,有值的话就取数组最后的执行
*/
while(this.failCallback.length)this.failCallback && this.failCallback.shift()(this.reason)
};
then(successCallback,failCallback){
if(this.status===FULFILLED){
successCallback(this.value)
}else if(this.status===REJECTED){
failCallback(this.reason)
}else{
/* 步骤2
-------------------------------------
将successCallback和failCallback函数push到数组中
*/
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
}
module.exports = MyPromise
- 验证代码:
//index.js
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve(200)
}, 500);
})
n.then((val)=>{
console.log('one-'+val)
},(erro)=>{
console.log(erro)
})
n.then((val)=>{
console.log('two-'+val)
},(erro)=>{
console.log(erro)
})
n.then((val)=>{
console.log('three-'+val)
},(erro)=>{
console.log(erro)
})
/*
one-200
two-200
three-200
*/
代码正常输出,证明无问题。
实现then方法的链式调用
还是先理一下需求,再进行开发:
then
方法的链式调用会返回一个Promise
,且then
方法的return
值会作为参数传给下一个then
代码实现
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
exector(this.resolve,this.reject)
};
status=PENDING;
value=undefined;
reason=undefined;
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
while(this.successCallback.length)this.successCallback.shift()(this.value)
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
while(this.failCallback.length)this.failCallback && this.failCallback.shift()(this.reason)
};
then(successCallback,failCallback){
/* 步骤1
------------------------
1.then方法会返回一个Promise,所以这里需要创建一个Promise,然后return回去
2. 我们先把 成功回调函数保存为n
3.然后在MyPromise类的外部再写一个resolvePromise做处理
*/
let prmoise2=new MyPromise((resolve,reject)=>{
if(this.status===FULFILLED){
//保存成功回调函数
let n=successCallback(this.value)
//传入resolvePromise函数中去做判断
resolvePromise(n,resolve,reject)
}else if(this.status===REJECTED){
failCallback(this.reason)
}else{
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return prmoise2;
}
}
/* 步骤2
---------------------------
//判断x是不是其实例的对象
*/
function resolvePromise(n,resolve,reject){
// 判断x是不是其实例对象,如果是就直接调用then方法
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
//普通值,直接调用resolve
resolve(n)
}
}
module.exports = MyPromise
:rocket:验证代码
const MyPromise=require('./MyPromise');
let n=new MyPromise((resolve,reject)=>{
resolve('lonjin')
})
function m(){
return new MyPromise((resolve,reject)=>{
console.log('------')
resolve('hello')
})
}
n.then((res)=>{
console.log(res)
return m();
})
.then((res)=>{
console.log(res)
})
/*
lonjin
------
hello
*/
:warning:特殊情况处理
:one: 如果then
方法返回的是自己的promise
对象,则会发生promise
的嵌套,这个时候程序会报错,如下代码:
var promise = new Promise((resolve, reject) => {
resolve(100)
})
var n = promise.then(value => {
console.log(value)
return n
})
// 100
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
:two: 同时还要处理一种情况,如果我们在new MyPromise
中传入的立即执行器中代码报错,以及then()
中写的代码报错,我们都需要捕获到,然后执行reject
:three: 之前一直是处理resolve
的情况,还需要处理一下reject
的情况
这时候我们需要改造一下刚才写的代码:
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
/* 步骤1
-------------------
捕获一下立即执行器中的错误
*/
constructor(exector){
try{
exector(this.resolve,this.reject)
}catch(e){
reject(e)
}
};
status=PENDING;
value=undefined;
reason=undefined;
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
/* 步骤6
-------------
由于修改了下面的successCallback,所以不需要传递this.value
*/
while(this.successCallback.length)this.successCallback.shift()()
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
/* 步骤7
-------------
由于修改了下面的failCallback,所以不需要传递this.reason
*/
while(this.failCallback.length)this.failCallback && this.failCallback.shift()()
};
then(successCallback,failCallback){
let prmoise2=new MyPromise((resolve,reject)=>{
if(this.status===FULFILLED){
/* 步骤2
---------------------
因为new Promise需要执行完成之后才有promise2,同步代码中没有pormise2,
所以这部分代码需要异步执行 ,我们把prmoise2传入resolvePromise函数中
去判断一下prmoise2是否等于n,同时需要捕获一下错误
*/
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else if(this.status===REJECTED){
/*
步骤3
---------------------
处理一下失败的情况
*/
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else{
/*
步骤5
---------------------
修改一下异步情况
*/
this.successCallback.push(()=>{
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
this.failCallback.push(()=>{
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
}
});
return prmoise2;
}
}
function resolvePromise(prmoise2,n,resolve,reject){
/* 步骤4
----------------
如果n和prmoise2相等 则返回错误提示
*/
if(prmoise2===n){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x是不是其实例对象
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
//普通值,直接调用resolve
resolve(n)
}
}
//导出MyPromise
module.exports = MyPromise
:rocket:验证代码
//验证1
//index.js
const MyPromise = require('./myPromise')
var promise = new MyPromise((resolve, reject) => {
resolve(100)
})
var p1 = promise.then(value => {
console.log(value)
return p1
})
p1.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro.message)
})
// 100
// Chaining cycle detected for promise #<Promise>
//验证2
var errofn = new MyPromise((resolve, reject) => {
throw new Error('执行器抛出异常!')
})
errofn.then((val)=>{
console.log(val)
},(erro)=>{
console.log(erro)
})
// 执行器错误
将then方法的参数变成可选参数
- 我们知道,调用
then()
时候也可以不传递任何参数,如下面这种情况
let promise =new Promise((resolve,reject)=>{
resolve('lonjin')
})
promise.then().then().then((value)=>{
console.log(value)
})
//lonjin
- 相当于这样:
promise
.then(value => value)
.then(value => value)
.then(value => value)
.then(value => console.log(value))
所以我们要把then
方法的参数改为可选参数,如果有参数就传入,如果没有返回value
:
代码实现
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
try{
exector(this.resolve,this.reject)
}catch(e){
reject(e)
}
};
status=PENDING;
value=undefined;
reason=undefined;
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
while(this.successCallback.length)this.successCallback.shift()()
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
while(this.failCallback.length)this.failCallback && this.failCallback.shift()()
};
then(successCallback,failCallback){
/*步骤1
----------------
判断参数是否存在
*/
successCallback=successCallback?successCallback:value=>value;
failCallback=failCallback?failCallback:reason=>{throw reason};
let prmoise2=new MyPromise((resolve,reject)=>{
if(this.status===FULFILLED){
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else if(this.status===REJECTED){
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else{
this.successCallback.push(()=>{
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
this.failCallback.push(()=>{
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
}
});
return prmoise2;
}
}
function resolvePromise(prmoise2,n,resolve,reject){
if(prmoise2===n){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
resolve(n)
}
}
module.exports = MyPromise
验证代码
const MyPromise = require('./myPromise')
let promise =new MyPromise((resolve,reject)=>{
resolve('lonjin')
})
promise.then().then().then((value)=>{
console.log(value)
})
//lonjin
Promise.all()方法实现
还是先分析一下all
方法:
function fn1(){
return new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('fn1')
}, 3000);
})
}
function fn2(){
return new Promise((resolve,reject)=>{
resolve('fn2')
})
}
Promise.all(['a','b',fn1(),fn2(),'e'])
.then((res)=>{
console.log(res)
},(erro)=>{
console.log(erro)
})
//[ 'a', 'b', 'fn1', 'fn2', 'e' ]
-
all
方法接收一个数组,其内部可以传入普通值
和Promise
对象 -
all
方法返回的也是一个Promise
对象,其返回值为一个数组 -
all
方法中传入的Promise
对象,如果都是成功,返回为成功,如果有一个失败,就会走失败的回调函数
分析完代码,我们就可以进行编写了,具体代码如下:
代码实现
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
try{
exector(this.resolve,this.reject)
}catch(e){
reject(e)
}
};
status=PENDING;
value=undefined;
reason=undefined;
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
while(this.successCallback.length)this.successCallback.shift()()
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
while(this.failCallback.length)this.failCallback && this.failCallback.shift()()
};
then(successCallback,failCallback){
successCallback=successCallback?successCallback:value=>value;
failCallback=failCallback?failCallback:reason=>{throw reason};
let prmoise2=new MyPromise((resolve,reject)=>{
if(this.status===FULFILLED){
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else if(this.status===REJECTED){
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else{
this.successCallback.push(()=>{
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
this.failCallback.push(()=>{
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
}
});
return prmoise2;
};
/*
all()实现all方法
*/
static all(array){
// 要返回的数组
let result=[];
//记录执行次数
let index=0;
//all方法返回的也是一个promise
return new MyPromise((resolve,reject)=>{
//定义一个存到result数组中的方法
function addItem(key,value){
result[key]=value;
index++;
//如果index等于传入array的长度,说明执行完成
if(index==array.length){
resolve(result)
}
}
//循环array
for(let i=0;i<array.length;i++){
//当前的参数
let current=array[i];
//判断一下当前的返回值是普通值还是promise
if(current instanceof MyPromise){
current.then(value=>addItem(i,value),reason=>reject(reason));
}else{
addItem(i,current)
}
}
})
}
}
function resolvePromise(prmoise2,n,resolve,reject){
if(prmoise2===n){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
resolve(n)
}
}
module.exports = MyPromise
Promise.resolve()方法实现
resolve
方法可以接受一个prmoise
对象,也可以接收一个普通值,如果是普通值需要包装成一个prmoise
返回。
代码实现
const PENDING='pending',
FULFILLED='fulfilled',
REJECTED='rejected';
class MyPromise{
constructor(exector){
try{
exector(this.resolve,this.reject)
}catch(e){
reject(e)
}
};
status=PENDING;
value=undefined;
reason=undefined;
successCallback=[];
failCallback=[];
resolve=value=>{
if(this.status!==PENDING)return;
this.status=FULFILLED;
this.value=value;
while(this.successCallback.length)this.successCallback.shift()()
};
reject=reason=>{
if(this.status!==PENDING)return;
this.status=REJECTED;
this.reason=reason;
while(this.failCallback.length)this.failCallback && this.failCallback.shift()()
};
then(successCallback,failCallback){
successCallback=successCallback?successCallback:value=>value;
failCallback=failCallback?failCallback:reason=>{throw reason};
let prmoise2=new MyPromise((resolve,reject)=>{
if(this.status===FULFILLED){
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else if(this.status===REJECTED){
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else{
this.successCallback.push(()=>{
setTimeout(() => {
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
this.failCallback.push(()=>{
setTimeout(() => {
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
}
});
return prmoise2;
};
static all(array){
let result=[];
let index=0;
return new MyPromise((resolve,reject)=>{
function addItem(key,value){
result[key]=value;
index++;
if(index==array.length){
resolve(result)
}
}
for(let i=0;i<array.length;i++){
let current=array[i];
if(current instanceof MyPromise){
current.then(value=>addItem(i,value),reason=>reject(reason));
}else{
addItem(i,current)
}
}
})
};
/*
resolve方法
*/
static resolve(value){
//判断value 是否为MyPromise的实例,如果是,直接返回
if( value instanceof MyPromise) return value;
//如果不是,return一个prmoise
return new MyPromise(resolve=>resolve(value))
}
}
function resolvePromise(prmoise2,n,resolve,reject){
if(prmoise2===n){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
resolve(n)
}
}
module.exports = MyPromise
代码验证
const MyPromise = require('./myPromise');
MyPromise.resolve('lonjin').then((res)=>{
console.log(res)
});
//lonjin
finally()方法实现
finally()
方法返回一个Promise
。在Promise
结束时,无论结果是fulfilled
或者是rejected
,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()
和catch()
中各写一次的情况。
- 返回的是
Promise
- 无论成功和失败都会执行
代码实现
//MyPromise中
finally(callback){
// 使用then方法拿到当前的promise的状态
return this.then(value=>{
/* 如果callback是一个异步的promise对象,我们还需要等待其执行完毕,所以需要用到静态方法resolve
把callback调用之后返回的promise传递过去,并且执行promise,且在成功之后返回value
*/
return MyPromise.resolve(callback()).then(()=>value)
},reason=>{
// 失败之后调用的then方法,然后把失败的原因返回出去
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
代码验证
const MyPromise = require('./myPromise')
function fn1(){
return new MyPromise((resolve,reject)=>{
setTimeout(() => {
reject('100')
}, 3000);
})
}
fn1().finally(()=>{
console.log('finally')
}).then((value)=>{
console.log(value)
},(erro)=>{
console.log(erro)
})
//finally
// 100
catch方法的实现
- catch方法是为了捕获promise对象的所有错误回调的
- 直接调用then方法,然后成功的地方传递undefined,错误的地方传递reason
- catch方法是作用在原型对象上的方法
代码实现
catch (failCallback) {
// 直接调用then方法,然后成功的地方传递undefined,错误的地方传递reason
return this.then(undefined, failCallback)
}
完整代码
完整代码在下方,所有的都加了注释,需要的直接复制到编辑器看吧!
//定义三个常量
const PENDING='pending', //等待
FULFILLED='fulfilled', //成功
REJECTED='rejected'; //失败
class MyPromise{
constructor(exector){
// 立即执行函数,传入resolve方法和reject方法
//同时捕获一下错误
try{
exector(this.resolve,this.reject)
}catch(e){
this.reject(e)
}
};
//定义一个初始状态
status=PENDING;
//保存成功后的值
value=undefined;
//保存失败后的值
reason=undefined;
//定义一个成功回调函数
successCallback=[];
//定义一个失败回调函数
failCallback=[];
//成功
resolve=value=>{
//判断当前状态是否为PENDING,如果不是就return
if(this.status!==PENDING)return;
//更改状态为fulfilled
this.status=FULFILLED;
//保存成功的返回值
this.value=value;
//判断成功回调是否存在,如果存在,直接调用
while(this.successCallback.length)this.successCallback.shift()()
};
//失败
reject=reason=>{
//判断当前状态是否为PENDING,如果不是就return
if(this.status!==PENDING)return;
//更改状态为rejected
this.status=REJECTED;
//保存失败的返回值
this.reason=reason;
//判断成功回调是否存在,如果存在,直接调用
while(this.failCallback.length)this.failCallback && this.failCallback.shift()()
};
//then方法会接收两个回调函数,分别为成功和失败的回调函数
then(successCallback,failCallback){
//处理then方法可选参数
successCallback=successCallback?successCallback:value=>value;
failCallback=failCallback?failCallback:reason=>{throw reason}
let prmoise2=new MyPromise((resolve,reject)=>{
//判断当前状态,然后调用相应的函数
if(this.status===FULFILLED){ //成功状态
//传入返回值
/*因为new Promise需要执行完成之后才有promise2,同步代码中没有pormise2,
所以这部分代码需要异步执行 */
setTimeout(() => {
//捕获错误
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else if(this.status===REJECTED){ //失败状态
//传入返回值
setTimeout(() => {
//捕获错误
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
}else{ //等待状态
//保存回调函数(考虑到异步情况)
this.successCallback.push(()=>{
setTimeout(() => {
//捕获错误
try{
let n=successCallback(this.value)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
this.failCallback.push(()=>{
setTimeout(() => {
//捕获错误
try{
let n= failCallback(this.reason)
resolvePromise(prmoise2,n,resolve,reject)
}catch(e){
reject(e)
}
}, 0);
});
}
});
return prmoise2;
};
// 直接调用then方法,然后成功的地方传递undefined,错误的地方传递reason
catch (failCallback) {
return this.then(undefined, failCallback)
}
finally(callback){
// 使用then方法拿到当前的promise的状态
return this.then(value=>{
/* 如果callback是一个异步的promise对象,我们还需要等待其执行完毕,所以需要用到静态方法resolve
把callback调用之后返回的promise传递过去,并且执行promise,且在成功之后返回value
*/
return MyPromise.resolve(callback()).then(()=>value)
},reason=>{
// 失败之后调用的then方法,然后把失败的原因返回出去
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
static all(array){
// 要返回的数组
let result=[];
//记录执行次数
let index=0;
//all方法返回的也是一个promise
return new MyPromise((resolve,reject)=>{
//定义一个存到result数组中的方法
function addItem(key,value){
result[key]=value;
index++;
if(index==array.length){
resolve(result)
}
}
//循环array
for(let i=0;i<array.length;i++){
//当前的参数
let current=array[i];
//判断一下当前的返回值是普通值还是promise
if(current instanceof MyPromise){
current.then(value=>addItem(i,value),reason=>reject(reason));
}else{
addItem(i,current)
}
}
})
};
static resolve(value){
//判断value 是否为MyPromise的实例,如果是,直接返回
if( value instanceof MyPromise) return value;
//如果不是,return一个prmoise
return new MyPromise(resolve=>resolve(value))
}
}
//判断x是不是其实例的对象
function resolvePromise(prmoise2,n,resolve,reject){
//如果n和prmoise2相等 则返回错误提示
if(prmoise2===n){
console.log('相等')
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x是不是其实例对象
if(n instanceof MyPromise){
n.then(resolve,reject)
}else{
//普通值,直接调用resolve
resolve(n)
}
}
//导出MyPromise
module.exports = MyPromise
结尾
文章如有错误欢迎指正。 👉关注前端365:分享前端小技巧以及开发过程中的一些问题,欢迎关注+收藏+点赞,感谢支持~