资讯专栏INFORMATION COLUMN

[译]async-await 数组循环的几个坑

warkiz / 759人阅读

摘要:译数组循环的几个坑原文地址原文作者在循环中使用循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。循环的情况问题如上述代码能够正常执行。但我还是喜欢循环带来的简洁和高可读性。

[译]async-await 数组循环的几个坑

原文地址:https://medium.com/dailyjs/th...

原文作者:Tory Walker

在 Javascript 循环中使用 async/ await 循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。让我们看看三个不同的例子,看看你应该注意什么,以及哪个循环最适合特定用例。

forEach 循环的情况
const urls = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2",
  "https://jsonplaceholder.typicode.com/todos/3"
];

async function getTodos() {
  await urls.forEach(async (url, idx) => { 
    const todo = await fetch(url);
    console.log(`Received Todo ${idx+1}:`, todo);
  });
  
  console.log("Finished!");
}

getTodos();

Finished!
Received Todo 2, Response: { ··· }
Received Todo 1, Response: { ··· }
Received Todo 3, Response: { ··· }

⚠️问题 1:

如上述代码能够正常执行。但是注意 Finished! 消息,被率先打印了。尽管我们使用了 await 但他仍然不会等待所有 await 执行完毕

⚠️ 问题 2:

然而,尽管 await 在循环中使用,但它并没有等待每个请求在执行下一个请求之前完成。请求不会按照顺序一步一步被发送出去。如果第一个请求的时间比以下请求的时间长,它仍然可以在最后完成。

因此,根据上述原因,forEach 在和 async/await 搭配使用的时候并不是一个靠得住的东西

Promise.all 方法

我们首先需要解决的就是等待所有循环执行完毕。await 操作符返回一个 promise,我们可以使用 Promise.all 方法去并行执行所有的请求。最后去 await 所有 promise 返回的结果

const urls = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2",
  "https://jsonplaceholder.typicode.com/todos/3"
];

async function getTodos() {
  const promises = urls.map(async (url, idx) => 
    console.log(`Received Todo ${idx+1}:`, await fetch(url))
  );

  await Promise.all(promises);

  console.log("Finished!");
}

getTodos();

Received Todo 1, Response: { ··· }
Received Todo 2, Response: { ··· }
Received Todo 3, Response: { ··· }
Finished!

我们解决了不等待所有请求执行完毕后打印 Finished!,看起来我们似乎也解决了请求顺序的问题。

实际上,上文中已经提到过,Promise.all 方法会按照并行的模式,将所有请求一次性全部发送出去,然后等待接收到全部结果后,按照顺序打印出来而已。它并不会按照顺序发送一个请求,收到结果后再发送下一个请求。

这非常适合不需要按照顺序发送的情况,但如果你想要的是串行发送请求那么 Promise.all 并不适合

for-of 循环

以上的两种方法并不能完美解决那两个问题。

for-of 循环则能够按照预期顺序执行——等待上一个 await 执行完毕后,再接着下一个。

const urls = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2",
  "https://jsonplaceholder.typicode.com/todos/3"
];

async function getTodos() {
  for (const [idx, url] of urls.entries()) {
    const todo = await fetch(url);
    console.log(`Received Todo ${idx+1}:`, todo);
  }

  console.log("Finished!");
}

getTodos();

Received Todo 1, Response: { ··· }
Received Todo 2, Response: { ··· }
Received Todo 3, Response: { ··· }
Finished!

我特别喜欢这种使代码保持线性的方法,这是使用 async/await 的关键优势之一。我觉得它比其他选择更容易阅读。

如果您不需要访问索引,则代码变得更加简洁:

for(ur url of urls){···}

使用for...of循环的一个主要缺点是它与Javascript中的其他循环选项相比性能不够好。但是,将性能参数用于await异步调用时,性能参数可以忽略不计,因为目的是在每个调用解析之前保持循环。我通常只使用for...of进行异步。

当然你也可以使用 for 循环得到 for-of 循环所有好处。但我还是喜欢 for-of 循环带来的简洁和高可读性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109032.html

相关文章

  • ES6系列文章 异步神器async-await

    摘要:有两个陌生的关键字,同时函数执行结果似乎返回了一个对象。用来表示函数是异步的,定义的函数会返回一个对象,可以使用方法添加回调函数。如果的是对象会造成异步函数停止执行并且等待的解决如果等的是正常的表达式则立即执行。 视频讲解 关于异步处理,ES5的回调使我们陷入地狱,ES6的Promise使我们脱离魔障,终于、ES7的async-await带我们走向光明。今天就来学习一下 async-a...

    miqt 评论0 收藏0
  • ajax中回调的几个坑

    摘要:在前端开发中,经常要用去拿后台接口返回的数据,总结几个的回调的常见问题,供大家参考爬坑。未定义,可能会造成的传入后台的数据乱码,可以加上如下代码在请求中约定好传到后台以及后台返回的数据类型,一般定义类型。 在前端开发中,经常要用ajax去拿后台接口返回的数据,总结几个ajax的回调的常见问题,供大家参考爬坑。 未定义contentType,可能会造成的传入后台的数据乱码,可以加上如下...

    huashiou 评论0 收藏0
  • ajax中回调的几个坑

    摘要:在前端开发中,经常要用去拿后台接口返回的数据,总结几个的回调的常见问题,供大家参考爬坑。未定义,可能会造成的传入后台的数据乱码,可以加上如下代码在请求中约定好传到后台以及后台返回的数据类型,一般定义类型。 在前端开发中,经常要用ajax去拿后台接口返回的数据,总结几个ajax的回调的常见问题,供大家参考爬坑。 未定义contentType,可能会造成的传入后台的数据乱码,可以加上如下...

    learn_shifeng 评论0 收藏0

发表评论

0条评论

warkiz

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<