摘要:更好的語(yǔ)義和分別表示異步和等待,比起和更容易理解。前邊聲明關(guān)鍵字,表示內(nèi)部有內(nèi)部操作,調(diào)用函數(shù)會(huì)返回一個(gè)對(duì)象。等價(jià)于其中函數(shù)就是自動(dòng)執(zhí)行器。
async函數(shù) 定義
async函數(shù)其實(shí)就是之前說(shuō)過(guò)的Generator的語(yǔ)法糖,用于實(shí)現(xiàn)異步操作。它是ES2017的新標(biāo)準(zhǔn)。
讀取兩個(gè)文件:
const fs = require("fs") const readFile = function(filename){ return new Promise(function(resolve,reject){ fs.readFile(filename,function(error,data)){ if(error) return reject(error) resolve(data) } }) } const gen = function* (){ const gen1 = yield readFile("../1.txt") const gen2 = yield readFile("../2.txt") console.log(gen1.toString()) console.log(gen2.toString()) }
如果使用async函數(shù)的話,會(huì)是這么寫(xiě)
const _readFile = async function(){ const r1 = await readFile("../3.txt") const r2 = await readFile("../4.txt") console.log(r1.toString()) console.log(r2.toString()) }
一般情況下,只是把Generator的*換成async,把yield換成await。
async函數(shù)是Generator函數(shù)的改進(jìn),具體體現(xiàn)在四點(diǎn)
1.內(nèi)置執(zhí)行器:
相對(duì)于Generator函數(shù)需要co模塊或者next()方法來(lái)作為執(zhí)行器執(zhí)行,async函數(shù)自帶執(zhí)行器,所以上邊的代碼只需要一句
_readFile()
可以執(zhí)行。
2.更好的語(yǔ)義:
async和await分別表示異步和等待,比起*和yield更容易理解。
3.更廣泛的適用性:
yield后邊只能跟Thunk函數(shù)或者Promise對(duì)象,但是在async函數(shù)中,可以跟Promise對(duì)象和基本數(shù)據(jù)類(lèi)型。
4.返回值是Promise
相比于Generator函數(shù)返回一個(gè)Iterator還需要遍歷,async直接返回一個(gè)Promise可以直接調(diào)用then方法和catch方法。
基本用法async函數(shù)返回一個(gè)Promise對(duì)象,可以使用then方法添加回調(diào),然后使用await關(guān)鍵字后,會(huì)等到異步操作執(zhí)行完在執(zhí)行后邊的語(yǔ)句。
async function getPriceByName(name){ const symbol = await getSymbod(name) const price = await getPrice(symbol) return price } getPriceByName("WUBA").then(function(result){ console.log(result) })
上邊的例子,是一個(gè)通過(guò)股票的名稱,獲得股票的代碼,再獲得價(jià)錢(qián)。前邊聲明async關(guān)鍵字,表示內(nèi)部有內(nèi)部操作,調(diào)用函數(shù)會(huì)返回一個(gè)Promise對(duì)象。
再看下一個(gè)例子,是一個(gè)指定多少毫秒后返回一個(gè)值。
function TimeOut(time){ return new Promise(function(resolve)){ setTimeout(resolve,time) } } async asyncTimeOut = function(value,time){ const t1 = await TimeOut(time) console.log(t1) } asyncTimeOut("hello",1000) asyncTimeOut("world",2000)
async函數(shù)的多種形式
函數(shù)表達(dá)式 const fun1 = async function(){ .... } 函數(shù)聲明 async function fun2(){ .... } 箭頭函數(shù) const fun3 = async () => { .... } 對(duì)象中的變量 let obj = { async fun4(){ .... } } obj.fun4() 類(lèi)的寫(xiě)法 class Async { constructor(){} async fun5(){ .... } } const a1 = new Async() a1.fun5().then()語(yǔ)法 返回一個(gè)Promise對(duì)象
說(shuō)過(guò)很多次了,async函數(shù)返回一個(gè)Promise對(duì)象。
函數(shù)return的值將會(huì)作為then方法的參數(shù)
async function show(){ return "123" } show().then((v) => console.log(v))
show方法返回的值會(huì)被作為then方法的參數(shù)而調(diào)用。
如果在async函數(shù)內(nèi)部拋出錯(cuò)誤,會(huì)被catch捕獲,這個(gè)時(shí)候Promise對(duì)象變成reject狀態(tài)。
async function show2(){ throw new Error("出錯(cuò)了") } show2().then( v => console.log(v), e => console.log(e) )Promise的狀態(tài)改變
async函數(shù)返回的Promise對(duì)象,必須等到函數(shù)內(nèi)部所有的await執(zhí)行完才會(huì)發(fā)生狀態(tài)的變化,也就是說(shuō),得等到所有await執(zhí)行完,才會(huì)執(zhí)行后續(xù)的then方法。
async function getText(url){ const response = await fetch(url) const text = await response.text() return text.match("../aa/[a-z]}")[1] //反正就是一個(gè)正則匹配 } const url = "...." getText(url).then(v => console.log(v))
這個(gè)例子說(shuō)明,得等到兩個(gè)awiat都執(zhí)行完才會(huì)console返回的數(shù)據(jù)。
await命令前邊說(shuō)過(guò),await命令后邊跟隨一個(gè)Promise對(duì)象。如果不是,會(huì)被轉(zhuǎn)成Promise對(duì)象。
async function show(){ return await "123" } show().then((v) => console.log(v))
如果await后邊的Promise對(duì)象變成了reject狀態(tài),會(huì)被后邊的catch()捕獲。
async function fun1() { return await Promise.reject("出錯(cuò)了") } fun1().catch(e => console.log(e))
如果async函數(shù)內(nèi)部有多個(gè)await,但是只要一個(gè)await返回的Promise對(duì)象變成了reject狀態(tài),則整個(gè)函數(shù)立刻捕獲異常。
如果想要前邊的正常拋出異常而不影響后邊的await語(yǔ)句執(zhí)行,可以把前邊的寫(xiě)進(jìn)一個(gè)try/catch中去。
async function fun2(){ try{ await Promise.reject("出錯(cuò)了") }catch(e){ } await Promise.resolev("hello") } fun2().then(v => console.log(v))使用的注意點(diǎn)
由于await后面跟隨的是Promise對(duì)象,所以對(duì)象可能會(huì)有兩個(gè)狀態(tài),一個(gè)resolve一個(gè)reject。所以,最好把a(bǔ)wait代碼放到try/catch語(yǔ)句中比較好。
async function fun3(){ try{ await asyncFun1() await asyncFun2() } catch(e){ console.log(e) } } // 還有另外一種寫(xiě)法 async function fun4(){ await asyncFun1().catch(e => console.log(e)) await asyncFun2().catch(e => console.log(e)) }
還是第一種方法更好一點(diǎn)。直接寫(xiě)進(jìn)try/catch語(yǔ)句中。
最好讓多個(gè)await后邊的異步操作同時(shí)發(fā)生,如果不是不存在先后順序的話。
let a1 = await get1() let a2 = await get2()
上邊的寫(xiě)法,get1執(zhí)行完之后才會(huì)執(zhí)行g(shù)et2,如果get1和get2沒(méi)有直接的關(guān)聯(lián),那樣會(huì)很浪費(fèi)時(shí)間。
//同時(shí)觸發(fā) let [a1,a2] = await Promise.all([get1(),get2()])
如果await放到async函數(shù)之外,就會(huì)報(bào)錯(cuò),只能放到async函數(shù)內(nèi)部。
async的原理原理也很簡(jiǎn)單,就是把Generator函數(shù)和自動(dòng)執(zhí)行器包裝在一個(gè)函數(shù)中。
async function fn(){ ..... } // 等價(jià)于 function fn(){ return spawn(function *(){ ..... }) }
其中spawn函數(shù)就是自動(dòng)執(zhí)行器。
function spawn(genF) { return new Promise(function(resolve, reject) { const gen = genF(); function step(nextF) { let next; try { next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } step(function() { return gen.next(undefined); }); }); }實(shí)例:按照順序完成異步操作
實(shí)際開(kāi)發(fā)中經(jīng)常會(huì)遇到各種異步操作,這里有一個(gè)例子。一次讀取一組url,然后按照讀取的順序返回結(jié)果。
function readUrls(urls) { const textPromise = urls.map(url => { fetch(url).then(response => response.text()) }) // 按照順序讀出 textPromise.reduce((chain,textPromise) => { return chain.then(() => textPromise) .then(text => console.log(text)); },Promise.resolve()) }
分析一下,上邊的代碼,用fetch同時(shí)讀取一種url,每個(gè)fetch操作都返回一個(gè)Promise對(duì)象,放入textPromise數(shù)組,然后reduce方法一次處理每個(gè)Promise對(duì)象,然后用then連接起來(lái),一次輸出結(jié)果。
缺點(diǎn):這種方法看起來(lái)不太好理解,不太直觀,用async函數(shù)會(huì)更好一點(diǎn)。
async function readUrls(urls){ for(const url of urls){ const response = await fetch(url) console.log(response.text()) } }
可以看到,代碼是大大簡(jiǎn)化了,但是會(huì)有一個(gè)新的問(wèn)題,就是必須等到前邊一個(gè)讀完了,才會(huì)讀取下一個(gè)數(shù)據(jù)。
function readUrls(urls){ const textPromise = urls.map(async url => { const response = await fetch(url) return response.text() }) } //按照順序輸出 for(const text of textPromise){ console.log(await text) }
上邊的函數(shù),雖然map方法的參數(shù)是async函數(shù),但卻是并發(fā)執(zhí)行的,因?yàn)閮?nèi)部是繼發(fā)執(zhí)行,不影響外部。在后邊的循環(huán)中使用了await,這樣,還是會(huì)依次輸出。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89737.html
摘要:傳統(tǒng)的異步方法回調(diào)函數(shù)事件監(jiān)聽(tīng)發(fā)布訂閱之前寫(xiě)過(guò)一篇關(guān)于的文章,里邊寫(xiě)過(guò)關(guān)于異步的一些概念。內(nèi)部函數(shù)就是的回調(diào)函數(shù),函數(shù)首先把函數(shù)的指針指向函數(shù)的下一步方法,如果沒(méi)有,就把函數(shù)傳給函數(shù)屬性,否則直接退出。 Generator函數(shù)與異步編程 因?yàn)閖s是單線程語(yǔ)言,所以需要異步編程的存在,要不效率太低會(huì)卡死。 傳統(tǒng)的異步方法 回調(diào)函數(shù) 事件監(jiān)聽(tīng) 發(fā)布/訂閱 Promise 之前寫(xiě)過(guò)一篇關(guān)...
摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...
摘要:在這里看尤雨溪大神的這篇小短文,非常精簡(jiǎn)扼要地介紹了當(dāng)前常用的。根據(jù)尤雨溪大神的說(shuō)法,的也只是的語(yǔ)法糖而已。對(duì)象有三種狀態(tài),,。對(duì)象通過(guò)和方法來(lái)規(guī)定異步結(jié)束之后的操作正確處理函數(shù)錯(cuò)誤處理函數(shù)。方便進(jìn)行后續(xù)的成功處理或者錯(cuò)誤處理。 最近在寫(xiě)一個(gè)自己的網(wǎng)站的時(shí)候(可以觀摩一下~Colors),在無(wú)意識(shí)中用callback寫(xiě)了一段嵌套了5重回調(diào)函數(shù)的可怕的代碼。回過(guò)神來(lái)的時(shí)候被自己嚇了一跳,...
摘要:讓我們使用它從數(shù)組中返回一個(gè)值數(shù)組在中,我們可以這樣做,這是一種更簡(jiǎn)單的方法最重要的部分是創(chuàng)建數(shù)組,該數(shù)組立即調(diào)用所有的我們?cè)谥骱瘮?shù)中等待這些。所以在我們真正等待完成之前,主函數(shù)就退出了。 原文:https://pouchdb.com/2015/03/0... PouchDB最棘手的方面之一是它的API是異步的。在Stack Overflow、Github和IRC上,我看到了不少困惑的...
摘要:第二次同理,遇到了第二個(gè)函數(shù)會(huì)停下來(lái),輸出的遍歷器對(duì)象值為,的值依然是。比如返回的遍歷器對(duì)象,都會(huì)有一個(gè)方法,這個(gè)方法掛在原型上。這三個(gè)函數(shù)共同的作用是讓函數(shù)恢復(fù)執(zhí)行。 Generator的語(yǔ)法 generator的英文意思是生成器 簡(jiǎn)介 關(guān)于Generator函數(shù),我們可以理解成是一個(gè)狀態(tài)機(jī),里面封裝了多種不同的狀態(tài)。 function* gener(){ yield hel...
閱讀 1091·2023-04-25 14:20
閱讀 1929·2021-11-24 10:20
閱讀 3859·2021-11-11 16:55
閱讀 3042·2021-10-14 09:42
閱讀 3543·2019-08-30 15:56
閱讀 1308·2019-08-30 15:55
閱讀 1138·2019-08-30 15:44
閱讀 844·2019-08-29 11:28