亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

詳解async/await 異步應用的常用場景

2024-05-06 16:50:51
字體:
來源:轉載
供稿:網友

前言

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 已經提前返回了,當然以上場景必須是這么做,但是有的時候我們并不需要這么做。

上面第一個場景中,我們只獲取到一張圖片,但是可能一個網頁中不止一張圖片,如果我們要把這些圖片存儲起來,其實是沒有必要等待圖片都并發請求回來后再處理,哪張圖片早回來就存儲哪張就行了

let imageUrls = ['href1', 'href2', 'href3']async function saveImages(imageUrls) {  await Promise.all(imageUrls.map(async imageUrl => {  let img = await getImage(imageUrl)  return await saveImage(img)}))  console.log('done')}
// 如果我們連存儲是否全部完成也不關心,也可以這么寫let imageUrls = ['href1', 'href2', 'href3']// saveImages() 連 async 都省了function saveImages(imageUrls) {  imageUrls.forEach(async imageUrl => {  let img = await getImage(imageUrl)  saveImage(img)  })}

可能有人會疑問 forEach 不是不能用于異步嗎,這個說法我也在剛接觸這個語法的時候就聽說過,很明顯 forEach 是可以處理異步的,只是是并發處理,map 也是并發處理,這個怎么用主要看你的實際場景,還要看你是否對結果感興趣

場景3.錯誤處理

一個請求發出,可以會遇到各種問題,我們是無法保證一定成功的,報錯是常有的事,所以處理錯誤有時很有必要, async/await 處理錯誤也非常直觀, 使用 try/catch 直接捕獲就可以了

async function imageCrawler(url) {  try {    let img = await getImage(url)    return img  } catch (error) {    console.log(error)  }}
// imageCrawler 返回的是一個 promise 可以這樣處理async function imageCrawler(url) {  let img = await getImage(url)  return img}imageCrawler(url).catch(err => {  console.log(err)})

可能有人會有疑問,是不是要在每個請求中都 try/catch 一下,這個其實你在最外層 catch 一下就可以了,一些基于中間件的設計就喜歡在最外層捕獲錯誤

async function ctx(next) {  try {    await next()  } catch (error) {    console.log(error)  }}

場景4. 超時處理

一個請求發出,我們是無法確定什么時候返回的,也總不能一直傻傻的等,設置超時處理有時是很有必要的

function timeOut(delay) {return new Promise((resolve, reject) => {  setTimeout(() => {  reject(new Error('不用等了,別傻了'))  }, delay)})}async function imageCrawler(url,delay) {try {  let img = await Promise.race([getImage(url), timeOut(delay)])  return img} catch (error) {  console.log(error)}}

這里使用 Promise.race 處理超時,要注意的是,如果超時了,請求還是沒有終止的,只是不再進行后續處理。當然也不用擔心,后續處理會報錯而導致重新處理出錯信息, 因為 promise 的狀態一經改變是不會再改變的

場景5. 并發限制

在并發請求的場景中,如果需要大量并發,必須要進行并發限制,不然會被網站屏蔽或者造成進程崩潰

async function getImages(urls, limit) {  let running = 0  let r  let p = new Promise((resolve, reject) => {  r = resolve  })  function run() {    if (running < limit && urls.length > 0) {      running++      let url = urls.shift();      (async () => {        let img = await getImage(url)        running--        console.log(img)        if (urls.length === 0 && running === 0) {          console.log('done')          return r('done')        } else {          run()        }      })()      run() // 立即到并發上限    }  }  run()  return await p}

總結

以上列舉了一些日常場景處理的代碼片段,在遇到比較復雜場景時,可以結合以上的場景進行組合使用,如果場景過于復雜,最好的辦法是使用相關的異步代碼控制庫。如果想更好地了解 async/await 可以先去了解 promise 和 generator, async/await 基本上是 generator 函數的語法糖,下面簡單的描述了一下內部的原理。

function delay(time) {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve(time)    }, time)  })}function *createTime() {  let time1 = yield delay(1000)  let time2 = yield delay(2000)  let time3 = yield delay(3000)  console.log(time1, time2, time3)}let iterator = createTime()console.log(iterator.next())console.log(iterator.next(1000))console.log(iterator.next(2000))console.log(iterator.next(3000))// 輸出{ value: Promise { <pending> }, done: false } { value: Promise { <pending> }, done: false } { value: Promise { <pending> }, done: false } 1000 2000 3000 { value: undefined, done: true }

可以看出每個 value 都是 Promise,并且通過手動傳入參數到 next 就可以設置生成器內部的值,這里是手動傳入,我只要寫一個遞歸函數讓其自動添進去就可以了

function run(createTime) {  let iterator = createTime()  let result = iterator.next()  function autoRun() {    if (!result.done) {      Promise.resolve(result.value).then(time => {      result = iterator.next(time)      autoRun()    }).catch(err => {      result = iterator.throw(err)      autoRun()      })    }  }  autoRun()}run(createTime)

promise.resove 保證返回的是一個 promise 對象 可迭代對象除了有 next 方法還有 throw 方法用于往生成器內部傳入錯誤,只要生成內部能捕獲該對象,生成器就可以繼承運行,類似下面的代碼

function delay(time) {  return new Promise((resolve, reject) => {    setTimeout(() => {      if (time == 2000) {      reject('2000錯誤')    }      resolve(time)    }, time)  })}function *createTime() {  let time1 = yield delay(1000)  let time2  try {    time2 = yield delay(2000)  } catch (error) {    time2 = error  }  let time3 = yield delay(3000)  console.log(time1, time2, time3)}

可以看出生成器函數其實和 async/await 語法長得很像,只要改一下 async/await 代碼片段就是生成器函數了

async function createTime() {  let time1 = await delay(1000)  let time2  try {    time2 = await delay(2000)  } catch (error) {    time2 = error  }  let time3 = await delay(3000)  console.log(time1, time2, time3)}function transform(async) { let str = async.toString() str = str.replace(/async/s+(function)/s+/, '$1 *').replace(/await/g, 'yield') return str}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久久久久久午夜| 日韩在线视频免费观看高清中文| 国产亚洲精品久久久优势| 国产精品一区二区久久久久| 日本久久亚洲电影| 日韩电影免费观看在线观看| 欧美性xxxx极品hd满灌| 成人激情电影一区二区| 日韩激情视频在线| 久久久久久久久久亚洲| 国产精品视频在线观看| 欧美成人四级hd版| 国产精品欧美一区二区三区奶水| 久久精品最新地址| 久久久免费观看| 亚洲区在线播放| 国产成人91久久精品| 亚洲综合在线播放| 国产精品久久久久久久天堂| 精品亚洲一区二区三区四区五区| 欧美精品videossex88| 69视频在线免费观看| 日韩亚洲综合在线| 2018国产精品视频| www.欧美三级电影.com| 亚洲国产精品嫩草影院久久| 亚洲精品美女在线观看播放| 欧美激情中文字幕乱码免费| 欧洲s码亚洲m码精品一区| 欧美日本黄视频| 久久免费视频在线| 欧美精品激情在线观看| 国产精品美女视频网站| 97热在线精品视频在线观看| 欧美乱妇高清无乱码| 国产午夜精品视频免费不卡69堂| 国产精品一区二区3区| 欧美性xxxxxxxxx| 成人激情免费在线| 国内外成人免费激情在线视频网站| 国产成人一区二区三区电影| 久久久综合免费视频| 国产一区在线播放| 亚洲欧美日韩成人| 欧美日韩中国免费专区在线看| 国色天香2019中文字幕在线观看| 国产精品嫩草视频| 日韩欧美亚洲国产一区| 国产精品一区二区久久国产| 国产视频精品xxxx| 色噜噜久久综合伊人一本| 欧美专区中文字幕| 欧美精品久久久久久久久久| 96pao国产成视频永久免费| 亚洲国产精品系列| 91欧美精品成人综合在线观看| 久久天天躁狠狠躁夜夜躁2014| 亚洲欧洲国产精品| 欧美大秀在线观看| 欧美—级a级欧美特级ar全黄| 免费91麻豆精品国产自产在线观看| 亚洲免费视频网站| 久久九九精品99国产精品| 国产在线一区二区三区| 日韩激情av在线播放| 欧美午夜精品伦理| 欧美午夜www高清视频| 91精品视频网站| 在线视频免费一区二区| 欧美性猛交xxxx乱大交极品| 欧美黑人xxxⅹ高潮交| 97人人爽人人喊人人模波多| 欧美电影免费播放| 在线播放日韩欧美| 国产成人在线亚洲欧美| 国产精品久久一区| 97视频在线观看视频免费视频| 超薄丝袜一区二区| 久久久久久国产精品久久| 亚洲国产精品人人爽夜夜爽| 国内精品400部情侣激情| 国产精品稀缺呦系列在线| 国产精品第一区| 精品国产一区二区三区四区在线观看| 亚洲精品电影在线| 精品在线小视频| 亚洲色图欧美制服丝袜另类第一页| 中文字幕亚洲国产| 黑人巨大精品欧美一区二区免费| 成人免费视频在线观看超级碰| 自拍偷拍亚洲一区| 日韩欧美一区二区在线| 日韩高清免费观看| 国产精品成人va在线观看| 欧美大全免费观看电视剧大泉洋| 久久久久久尹人网香蕉| 国产精品18久久久久久麻辣| 国产精品一区二区三区久久久| 国产精品电影久久久久电影网| 欧美在线国产精品| 日韩经典中文字幕在线观看| 国产精品吴梦梦| 精品亚洲男同gayvideo网站| 亚洲人成电影网| 日韩一区二区三区在线播放| 98视频在线噜噜噜国产| 精品国产电影一区| 国产精品福利在线观看网址| 91久久在线播放| 亚洲国产天堂网精品网站| 欧美一区第一页| 日韩国产精品亚洲а∨天堂免| 中文字幕日韩精品在线观看| 欧美黄色小视频| 欧美黑人极品猛少妇色xxxxx| 高清欧美电影在线| 日韩高清电影免费观看完整| 久久久免费精品| 欧美超级乱淫片喷水| 久久人体大胆视频| 日韩欧美一区视频| 久久久久日韩精品久久久男男| 国产精品丝袜久久久久久不卡| 日韩经典中文字幕在线观看| 国产日韩欧美夫妻视频在线观看| 国产精品日韩欧美| 欧洲美女7788成人免费视频| 性色av一区二区咪爱| 亚洲老板91色精品久久| 日韩美女av在线免费观看| 国产欧美婷婷中文| 久久久久久69| 亚洲毛片在线看| 国产精品久久999| 中文字幕在线日韩| 国产精品精品视频| 亚洲精品久久久久| 久久国产一区二区三区| 欧美日韩性生活视频| 国产精品高精视频免费| 亚洲一区中文字幕在线观看| 青青久久av北条麻妃黑人| 欧洲永久精品大片ww免费漫画| 国产成人精品在线观看| 91久久久久久久久久| 久久精品福利视频| 日韩精品在线免费播放| 热久久这里只有精品| 97免费在线视频| 欧美放荡办公室videos4k| 久久91亚洲精品中文字幕奶水| 国产欧美精品va在线观看| 久久精品成人动漫| 91沈先生在线观看| 日本久久久久久久久| 日韩欧美成人精品| 中文字幕日韩av综合精品| 57pao国产精品一区| 亚洲xxx视频| 97成人超碰免| 国产精品日日摸夜夜添夜夜av| 久久69精品久久久久久国产越南| 久久久成人精品| 欧美午夜宅男影院在线观看|