文章目录
注意异步操作和处理异常
起步构建
状态、值、executor、resolve、reject
由于状态只改变一次,所以在resolve和reject改变状态之前要先判断当前是否为pending状态。
注意处理异常:如在executor中调用resolve或reject的时候传入未定义变量。因此需要在executor外层加上try-catch捕获异常。将报错信息作为rejected状态下promise的值。
class myPromise{
static PENDING='pending';
static FULLFILLED='fullfilled';
static REJECTED='rejected';
constructor(executor){
this.status=myPromise.PENDING;
this.value=null;
try {
executor(this.resolve.bind(this),this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value){
if(this.status==myPromise.PENDING){
this.status=myPromise.FULLFILLED;
this.value=value;
}
}
reject(reason){
if(this.status==myPromise.PENDING){
this.status=myPromise.REJECTED;
this.value=reason;
}
}
}
测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src='myPromise.js'></script>
<script>
const p=new myPromise((resolve,reject)=>{
resolve('成功啦');
});
console.log(p);
</script>
</body>
</html>
const p=new myPromise((resolve,reject)=>{
resolve(a);
});
console.log(p);
then()、链式调用
- 调用then的时候传入的参数可能不是函数类型,这个时候就需要自定义成功或者失败的回调。由于then具有穿透功能,因此当未传入回调时,直接返回当前value值
if(typeof onFullfilled!='function'){
onFullfilled=()=>this.value;
}
if(typeof onRejected!='function'){
onRejected=()=>this.value;
}
-
then方法返回值是一个新的promise
-
异步执行(executor中的异步性、resolve、reject)、异常处理
-
在executor中加定时器(setTimeout会将resolve放入回调队列,等其他操作顺序执行完之后才调用),调用then的时候当前promise仍是pending状态。由于每个promise都必定会经过状态为pending的时候,因此我们可以定义一个callbacks数组存储将要被调用的onFullfilled、onRejected回调,此操作放在pending状态的时候执行。当状态改变时将callbacks数组中的回调全部调出来执行,此操作在resolve()和reject()中处理。
- 测试——没加callbacks处理的时候:
const p=new myPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('成功');
},100);
});
const p1=p.then(value=>{
console.log(value);
});
console.log(p1);
- 处理后:
then(onFullfilled,onRejected){
if(typeof onFullfilled!='function'){
onFullfilled=()=>this.value;
}
if(typeof onRejected!='function'){
onRejected=()=>this.value;
}
return new myPromise((resolve,reject)=>{
if(this.status==myPromise.PENDING){
this.callbacks.push({
Full:value=>{
try {
let result=onFullfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
},
Reject:reason=>{
try {
let result=onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
}
});
}
if(this.status==myPromise.FULLFILLED){
setTimeout(()=>{
try {
let result=onFullfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
});
}
if(this.status==myPromise.REJECTED){
setTimeout(()=>{
try {
let result=onRejected(this.value);
resolve(result);
} catch (error) {
reject(error);
}
});
}
});
}
then中回调的返回值类型
无论当前promise成功与否,都返回一个成功的promise,一般情况下,成功/失败的返回值即作为新的promise的值,若返回的是promise对象(通过instanceof判断),那么将该promise对象的值作为新promise的值(此处未处理当前promise中抛出异常的情况)
处理返回promise的情况(resolve):
try {
let result=onFullfilled(value);
if(result instanceof myPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch (error) {
reject(error);
}
测试(then穿透、resolve异步、链式、then回调返回promise):
const p=new myPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('成功啦');
},100);
});
p.then()
.then(value=>{
console.log(value);
return new myPromise((resolve,reject)=>{
resolve('成功回调返回的promise又成功啦');
})
})
.then(value=>{
console.log(value);
});
console.log('输出在最后');
代码优化、返回约束
then返回的promise不能是then相同的peomise(可输出)
而我们目前的promise是没有这个功能的
系统Promise:
const p=new Promise((resolve,reject)=>{
resolve('成功啦');
});
const res=p.then(value=>{
// console.log(res);
return res;
});
解决方法:
在then中的回调函数中判断返回的promise是否是当前promise,是则抛出异常,并且以上代码多处重复,可通过封装函数,将promise和回调返回结果result作为参数传递。
parse(promise,result,resolve,reject){
if(promise==result){
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
try {
if(result instanceof myPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch (error) {
reject(error);
}
}
定义一个变量promise存then()中要返回的promise,并且在then末尾返回该变量
then(onFullfilled,onRejected){
if(typeof onFullfilled!='function'){
onFullfilled=()=>this.value;
}
if(typeof onRejected!='function'){
onRejected=()=>this.value;
}
const promise=new myPromise((resolve,reject)=>{
if(this.status==myPromise.PENDING){
this.callbacks.push({
Full:value=>{
this.parse(promise,onFullfilled(value),resolve,reject);
},
Reject:reason=>{
this.parse(promise,onRejected(reason),resolve,reject);
}
});
}
if(this.status==myPromise.FULLFILLED){
setTimeout(()=>{
this.parse(promise,onFullfilled(this.value),resolve,reject);
});
}
if(this.status==myPromise.REJECTED){
setTimeout(()=>{
this.parse(promise,onRejected(this.value),resolve,reject);
});
}
});
return promise;
}
测试:
const p=new myPromise((resolve,reject)=>{
resolve('成功啦');
});
const res=p.then(value=>{
console.log(res);
return res;
});
静态resolve()和reject()
静态的resolve()和reject()的实现和then()中的回调类似
static resolve(value){
return new myPromise((resolve,reject)=>{
if(value instanceof myPromise){
value.then(resolve,reject);
}else{
resolve(value);
}
})
}
static reject(reason){
return new myPromise((resolve,reject)=>{
reject(reason);
})
}
all(promises)
all()参数为一个promise数组,当且仅当promises数组中所有promise都成功时才返回一个成功的promise,否则为失败。
实现:遍历循环promises数组,执行每个promise的then方法,定义一个values数组存放成功的值,若values的数组大小和promises大小相等就说明所有promise都成功,此时返回一个成功的promise,其值即values数组,若有promise失败则直接调用reject()返回一个失败的promise
static all(promises){
let values=[];
return new myPromise((resolve,reject)=>{
promises.forEach(promise => {
promise.then(value=>{
values.push(value);
if(values.length==promises.length){
resolve(values);
}
},reason=>{
reject(reason);
});
});
})
}
测试:
- 全部成功的情况:
const p1=myPromise.resolve('成功啦');
const p2=myPromise.resolve('又成功啦');
myPromise.all([p1,p2]).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
});
- 含失败情况
const p1=myPromise.resolve('成功啦');
const p2=myPromise.resolve('又成功啦');
const p3=myPromise.reject('失败啦');
myPromise.all([p1,p2,p3]).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
});
race(promises)
race()的参数也是一个promise数组,该方法根据数组中最先执行完的promise返回一个新的promise,其实只需要遍历循环promises数组,每个元素执行一次then方法就好了
static race(promises){
return new Promise((resolve,reject)=>{
promises.forEach(promise=>{
promise.then(value=>{
resolve(value);
},reason=>{
reject(reason);
});
})
})
}
测试:
const p1=new myPromise((resovle,reject)=>{
setTimeout(()=>{
resovle('成功啦');
},100);
});
const p2=new myPromise((resovle,reject)=>{
setTimeout(()=>{
reject('失败啦');
},200);
})
myPromise.race([p1,p2]).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
});
完整代码
class myPromise{
static PENDING='pending';
static FULLFILLED='fullfilled';
static REJECTED='rejected';
constructor(executor){
this.status=myPromise.PENDING;
this.value=null;
this.callbacks=[];
try {
executor(this.resolve.bind(this),this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value){
if(this.status==myPromise.PENDING){
this.status=myPromise.FULLFILLED;
this.value=value;
setTimeout(()=>{
this.callbacks.map(callback=>{
callback.Full(value);
})
});
}
}
reject(reason){
if(this.status==myPromise.PENDING){
this.status=myPromise.REJECTED;
this.value=reason;
setTimeout(()=>{
this.callbacks.map(callback=>{
callback.Reject(reason);
})
});
}
}
then(onFullfilled,onRejected){
if(typeof onFullfilled!='function'){
onFullfilled=()=>this.value;
}
if(typeof onRejected!='function'){
onRejected=()=>this.value;
}
const promise=new myPromise((resolve,reject)=>{
if(this.status==myPromise.PENDING){
this.callbacks.push({
Full:value=>{
this.parse(promise,onFullfilled(value),resolve,reject);
},
Reject:reason=>{
this.parse(promise,onRejected(reason),resolve,reject);
}
});
}
if(this.status==myPromise.FULLFILLED){
setTimeout(()=>{
this.parse(promise,onFullfilled(this.value),resolve,reject);
});
}
if(this.status==myPromise.REJECTED){
setTimeout(()=>{
this.parse(promise,onRejected(this.value),resolve,reject);
});
}
});
return promise;
}
parse(promise,result,resolve,reject){
if(promise==result){
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
try {
if(result instanceof myPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch (error) {
reject(error);
}
}
static resolve(value){
return new myPromise((resolve,reject)=>{
if(value instanceof myPromise){
value.then(resolve,reject);
}else{
resolve(value);
}
})
}
static reject(reason){
return new myPromise((resolve,reject)=>{
reject(reason);
})
}
static all(promises){
let values=[];
return new myPromise((resolve,reject)=>{
promises.forEach(promise => {
promise.then(value=>{
values.push(value);
if(values.length==promises.length){
resolve(values);
}
},reason=>{
reject(reason);
});
});
})
}
static race(promises){
return new Promise((resolve,reject)=>{
promises.forEach(promise=>{
promise.then(value=>{
resolve(value);
},reason=>{
reject(reason);
});
})
})
}
}