前言
async/await 語法用看起來像寫同步代碼的方式來優(yōu)雅地處理異步操作,但是我們也要明白一點,異步操作本來帶有復(fù)雜性,像寫同步代碼的方式并不能降低本質(zhì)上的復(fù)雜性,所以在處理上我們要更加謹(jǐn)慎, 稍有不慎就可能寫出不是預(yù)期執(zhí)行的代碼,從而影響執(zhí)行效率。下面將簡單地描述一下一些日常常用場景,加深對 async/await 認(rèn)識
最普遍的異步操作就是請求,我們也可以用 setTimeOut 來簡單模擬異步請求。
場景1. 一個請求接著一個請求
相信這個場景是最常遇到,后一個請求依賴前一個請求,下面以爬取一個網(wǎng)頁內(nèi)的圖片為例子進(jìn)行描述,使用了 superagent 請求模塊, cheerio 頁面分析模塊,圖片的地址需要分析網(wǎng)頁內(nèi)容得出,所以必須按順序進(jìn)行請求。
const request = require('superagent')const cheerio = require('cheerio')// 簡單封裝下請求,其他的類似function getHTML(url) {// 一些操作,比如設(shè)置一下請求頭信息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 格式的數(shù)據(jù) // 處理圖片}handler(url)上面就是一個簡單的獲取圖片數(shù)據(jù)的場景,圖片數(shù)據(jù)是加載進(jìn)內(nèi)存中,如果只是簡單的存儲數(shù)據(jù),可以用流的形式進(jìn)行存儲,以防止消耗太多內(nèi)存。
其中 await getHTML 是必須的,如果省略了 await 程序就不能按預(yù)期得到結(jié)果。執(zhí)行流程會先執(zhí)行 await 后面的表達(dá)式,其實際返回的是一個處于 pending 狀態(tài)的 promise,等到這個 promise 處于已決議狀態(tài)后才會執(zhí)行 await 后面的操作,其中的代碼執(zhí)行會跳出 async 函數(shù),繼續(xù)執(zhí)行函數(shù)外面的其他代碼,所以并不會阻塞后續(xù)代碼的執(zhí)行。
場景2.并發(fā)請求
有的時候我們并不需要等待一個請求回來才發(fā)出另一個請求,這樣效率是很低的,所以這個時候就需要并發(fā)執(zhí)行請求任務(wù)。下面以一個查詢?yōu)槔?先獲取一個人的學(xué)校地址和家庭住址,再由這些信息獲取詳細(xì)的個人信息,學(xué)校地址和家庭住址是沒有依賴關(guān)系的,后面的獲取個人信息依賴于兩者
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 里面的異步請求都會并發(fā)執(zhí)行,并等到數(shù)據(jù)都準(zhǔn)備后返回相應(yīng)的按數(shù)據(jù)順序返回的數(shù)組,這里最后處理獲取信息的時間,由并發(fā)請求中最慢的請求決定,例如 getSchoolAdr 遲遲不返回數(shù)據(jù),那么后續(xù)操作只能等待,就算 getHomeAdr 已經(jīng)提前返回了,當(dāng)然以上場景必須是這么做,但是有的時候我們并不需要這么做。
新聞熱點
疑難解答
圖片精選