为啥突然要记录下这个Promise链式调用呢?我觉得有必要强调一下。
在网络上大多数对Promise链式调用都是说下面这个代码(代码块1)
new Promise((resolve,reject)=>{
resolve({data:1})
}).then(res=>{
return res;
})
.then(res=>{
return res;
})
.then(res=>{
return res;
})
//......省略100个then
.then(res=>{
return res;
})
.then(res=>{
return res;
})
这种then不断接下去的一种形式,其实大多数情况下够用了。
最近在学习axios的实现,遇到了一种很有意思的链式调用方式,场景如下:
- let arr=[请求拦截器,请求拦截器,发起请求,响应拦截器,响应拦截器]
- arr的元素格式如下:{resolve:()=>{},reject:()=>{}} ,这是所有数组元素的实现协议,并且函数必须返回Promise.reject或则Promise.resolve
目标:
- 按顺序执行所有arr里面的resolve函数,
- 如果中途遇到reject情况可以,在arr最后一个函数执行后catch错误信息
- 如果都通过情况,可以通过then获取最终结果
- 支持异步和同步
实现代码:
var arr = [];//函数链,
var result = 1;//被函数链操作的数据
for (let i = 0; i < 5; i++) {
arr.push({
resolve: () => {
if (i % 2 == 0) {
return new Promise((resolve, reject) => {
setTimeout(()=>{
result+=1;
resolve({data:result,respone:{code:0}});
},200)
// reject({respone:{code:1}}) 如果是错误就触发reject外卖可以获取到
})
}
else {
result += 1;
return { data: result }
}
},
reject: () => {
result += 1;
return { data: result }
}
})
}
let promise = Promise.resolve({ data: "1" });
while (arr.length) {
let { resolve, reject } = arr.shift();
console.log(resolve, reject)
/**
* then方法的第一个参数是resolved状态的回调函数,
* 第二个参数(可选)是rejected状态的回调函数。
*/
/**
* then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。
* 因此可以采用链式写法,即then方法后面再调用另一个then方法。
*/
promise = promise.then(resolve, reject)
}
promise.then((resolve, reject) => {
console.log("resolve", resolve) // {data: 6,respone:{code:0}}
}).catch(e=>{
console.log("err",e)
})
上面数组里面的reject函数可以捕获到上一个原生的错误信息,并返回给下一个元素,具体可以如下实现
var arr = [];//函数链,
var result = 1;//被函数链操作的数据
for (let i = 0; i < 5; i++) {
arr.push({
resolve: () => {
if (i % 2 == 0) {
return new Promise((resolve, reject) => {
// setTimeout(()=>{
// result+=1;
// resolve({data:result,respone:{code:0}});
// },200)
reject({respone:{code:1,index:i}}) //如果是错误就触发reject外卖可以获取到
})
}
else {
result += 1;
return { data: result }
}
},
reject: (e) => {
console.log("上一个原生的错误",e)
result += 1;
//========重点看这里
//如果想下个元素不进入reject,可以返回resolve
//但是这样也会有弊端,不会触发最后一个原生的catch,也无法处理异常
return Promise.reject({ data: result,error:"reject的信息" })
}
})
}
let promise = Promise.resolve({ data: "1" });
while (arr.length) {
let { resolve, reject } = arr.shift();
console.log(resolve, reject)
/**
* then方法的第一个参数是resolved状态的回调函数,
* 第二个参数(可选)是rejected状态的回调函数。
*/
/**
* then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。
* 因此可以采用链式写法,即then方法后面再调用另一个then方法。
*/
promise = promise.then(resolve, reject)
}
promise.then((resolve, reject) => {
console.log("resolve", resolve) // {data: 6,respone:{code:0}}
}).catch(e=>{
console.log("err",e)
})
深入解说:
- 本质上:这段代码和代码块1的功能是一样的,实际执行的程序和最终的效果依旧是then.then.then这种结果
- 区别是:在代码层面解决了链式里面所有函数的依赖,不需要把函数都写在then里面一层接一层的堆叠代码
- 减少函数和promise.then的解耦
以下代码扮演中介者的角色,把promise.then和对应的函数糅合到一块,生成如代码块1那样的程序,解除promise.then和对应函数的耦合,让他们不需要相互认识,让开发者专心写对应的函数功能&&不需要关系执行过程和次序
while (arr.length) {
//...
}