首页 > 语言 > JavaScript > 正文

详解async/await 异步应用的常用场景

2024-05-06 15:39:35
字体:
来源:转载
供稿:网友

前言

async/await 语法用看起来像写同步代码的方式来优雅地处理异步操作,但是我们也要明白一点,异步操作本来带有复杂性,像写同步代码的方式并不能降低本质上的复杂性,所以在处理上我们要更加谨慎, 稍有不慎就可能写出不是预期执行的代码,从而影响执行效率。下面将简单地描述一下一些日常常用场景,加深对 async/await 认识
最普遍的异步操作就是请求,我们也可以用 setTimeOut 来简单模拟异步请求。

场景1. 一个请求接着一个请求

相信这个场景是最常遇到,后一个请求依赖前一个请求,下面以爬取一个网页内的图片为例子进行描述,使用了 superagent 请求模块, cheerio 页面分析模块,图片的地址需要分析网页内容得出,所以必须按顺序进行请求。

const request = require('superagent')const cheerio = require('cheerio')// 简单封装下请求,其他的类似function getHTML(url) {// 一些操作,比如设置一下请求头信息return superagent.get(url).set('referer', referer).set('user-agent', userAgent)}// 下面就请求一张图片async function imageCrawler(url) {  let res = await getHTML(url)  let html = res.text  let $ = cheerio.load(html)  let $img = $(selector)[0]  let href = $img.attribs.src  res = await getImage(href)  retrun res.body}async function handler(url) {  let img = await imageCrawler(url)  console.log(img) // buffer 格式的数据  // 处理图片}handler(url)

上面就是一个简单的获取图片数据的场景,图片数据是加载进内存中,如果只是简单的存储数据,可以用流的形式进行存储,以防止消耗太多内存。

其中 await getHTML 是必须的,如果省略了 await 程序就不能按预期得到结果。执行流程会先执行 await 后面的表达式,其实际返回的是一个处于 pending 状态的 promise,等到这个 promise 处于已决议状态后才会执行 await 后面的操作,其中的代码执行会跳出 async 函数,继续执行函数外面的其他代码,所以并不会阻塞后续代码的执行。

场景2.并发请求

有的时候我们并不需要等待一个请求回来才发出另一个请求,这样效率是很低的,所以这个时候就需要并发执行请求任务。下面以一个查询为例,先获取一个人的学校地址和家庭住址,再由这些信息获取详细的个人信息,学校地址和家庭住址是没有依赖关系的,后面的获取个人信息依赖于两者

 async function infoCrawler(url, name) {    let [schoolAdr, homeAdr] = await Promise.all([getSchoolAdr(name), getHomeAdr(name)])    let info = await getInfo(url + `?schoolAdr=${schoolAdr}&homeAdr=${homeAdr}`)    return info  }

上面使用的 Promise.all 里面的异步请求都会并发执行,并等到数据都准备后返回相应的按数据顺序返回的数组,这里最后处理获取信息的时间,由并发请求中最慢的请求决定,例如 getSchoolAdr 迟迟不返回数据,那么后续操作只能等待,就算 getHomeAdr 已经提前返回了,当然以上场景必须是这么做,但是有的时候我们并不需要这么做。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选