开题
本文主要是列举一下使用js async/await 方法发送串行/并行请求的不同方法。以及容易错误的地方。
准备工作
首先我们先用Promise准备一个模拟发送请求函数 以及 一个urls数组。
const allRequests = [
"http://jsonplaceholder.typicode.com/posts/1",
"http://jsonplaceholder.typicode.com/posts/2",
"http://jsonplaceholder.typicode.com/posts/3",
"http://jsonplaceholder.typicode.com/posts/4",
"http://jsonplaceholder.typicode.com/posts/5",
"http://jsonplaceholder.typicode.com/posts/6",
];
function fetch(url){
return new Promise((res, rej)=>{
console.log('start fetching '+url)
setTimeout(()=>{
res(url);
console.log('end fetching '+url)
}, 2000)
})
}
function fetchError(url){
return new Promise((res, rej)=>{
console.log('start fetching '+url)
setTimeout(()=>{
rej("fetchError: "+ url);
console.log('end fetching '+url)
}, 2000)
})
}
//串行
async function serialFlow(){
await fetch(allRequests[0]);
await fetch(allRequests[1]);
}
serialFlow()
//得到的输出结果是:
//start fetching http://jsonplaceholder.typicode.com/posts/1
//等待。。。。
//end fetching http://jsonplaceholder.typicode.com/posts/1
//start fetching http://jsonplaceholder.typicode.com/posts/2
//等待。。。。
//end fetching http://jsonplaceholder.typicode.com/posts/2
//从这个结果可以看出第一个请求返回结果之后,第二个请求才开始。
//加入第一个请求需要等待一个小时才返回结果,那么第二个请求就等一个小时之后才发送。
//如果第一个请求永远没有返回,那么第二个请求就不会发出。
//我们可以通过修改setTimeout里面的等待时间或者去掉promise中的res(url)来自己验证。
然后我们再来看一下并行。针对上面串行的例子,我们换一种写法便可以实现并行。
async function parallelFlow(){
const res1 = fetch(1);
const res2 = fetch(2);
}
parallelFlow();
//返回的结果如下:
//start fetching 1
//start fetching 2
//end fetching 2
//end fetching 1
但是如果我们要对fetch的返回结果进行处理应该怎么做呢?如果我们在parallelFlow打印res1我们会发现返回的是 Promise { },因此我们需要将Promise的状态改为resolved。可以这样做。
async function parallelFlow(){
const res1 = fetch(allRequests[0]);
const res2 = fetch(allRequests[1]);
const r1 = await res1;
const r2 = await res2;
console.log(r1 +" "+ r2)
}
现在看起来似乎实现了我们想要的简单并行发送请求,但是这里需要注意的点是,如果请求有错误的时候的处理。
async function errorHandlingParalle(){
try{
fetchError(allRequests[0])
}catch(e){
console.error(e)
}
}
async function errorHandlingSequence(){
try{
await fetchError(allRequests[0])
}catch(e){
console.error(e)
}
}
errorHandlingParalle()
errorHandlingSequence()
// 我们可以发现在errorHandlingSequence捕捉到了错误理由,
// 虽然我们在errorHandlingParalle里面加了 try catch 块,但是错误却并没有被捕捉到。
为了避免以上并行请求无法捕捉错误的情况发生,我们可以改造一下上面的代码
async function request(url){
try{
const res = await fetchError(url);
return res;
}catch(e){
console.error('request error '+ e)
}
}
async function errorHandlingParalle(){
try{
request(allRequests[0]);
request(allRequests[1]);
}catch(e){
console.error('err ',e)
}
}
// 或者如果不需要在 errorHandlingParalle 显示新的错误信息的话。也可以直接去掉try catch block
async function errorHandling(){
request(allRequests[0]);
request(allRequests[1]);
}
errorHandlingParalle()
/* 结果
start fetching http://jsonplaceholder.typicode.com/posts/1
start fetching http://jsonplaceholder.typicode.com/posts/2
end fetching http://jsonplaceholder.typicode.com/posts/1
request error fetchError: http://jsonplaceholder.typicode.com/posts/1
end fetching http://jsonplaceholder.typicode.com/posts/2
request error fetchError: http://jsonplaceholder.typicode.com/posts/2
*/
话外
串行也可以使用递归来实现。如下
async function requestRecursive(index){
if(index >= allRequests.length) return;
try{
await fetch(allRequests[index]);
requestRecursive(++index);
}catch(e){
console.error('err ',e)
}
}
但是这种递归的写法的特点是,如果任意一个请求返回有错误,进入catch里面就会停止继续递归发送请求。 因此可以改写成
async function requestRecursive(index){
if(index >= allRequests.length) return;
try{
await fetchError(allRequests[index]);
}catch(e){
console.error('err ',e)
}
requestRecursive(++index);
}
//或者可以同上面的并行模式的处理方式,如果不需要在显示新的错误信息的话。也可以直接去掉try catch block改成
async function requestRecursive(index){
if(index >= allRequests.length) return;
await request(allRequests[index]);
requestRecursive(++index);
}