簡談對ES7的async和await的理解
如果遇到過深度回撥的朋友一定對JS的回撥地獄再熟悉不過了,舉個例子說(如果我的列子不恰當盡請諒解),常見的就是省市區級聯吧,假如我要獲取一個縣級市的資訊,那麼我首先得獲得它所在的省的資訊,當取得省的資訊以後,再拉去地級市的資訊,當獲得地級市的資訊以後,然後才有可能獲取到它的資訊。這就是典型的深度回撥的業務場景。這使得開發人員變得痛苦不堪,程式碼的質量難以得到保證。
對此,ES6中引入了一個Promise物件來解決此類問題(本文只做大概的講解),Promise,中文是諾言的意思,表示一段時間(pending)之後一定會獲得的結果(resolved狀態或者說是fullfilled狀態),當然有可能獲得的結果是錯誤的(rejected)。語法是:
function asyncReadFile() { return new Promise((resolve, reject) => { var counter = 0; var timer = setInterval(() => { counter++; console.log({ counter }) if (counter >= 3) { clearInterval(timer); resolve('hello world'); } }, 1000) }) }
然後我們通過asyncReadFile().then(result => { console.log(result) }) 打印出hello world!。
對於之前的省市縣級聯的業務,我們可以利用Promise改寫成:
getProvinces().then(result => { console.log('省級行政區域的資訊為:' + result) return getCities() }).then(result => { console.log('地級行政區域的資訊為:' + result) return getAreas() }).then(result => { console.log('縣級行政區域的資訊為:' + result) })
假設getProvince、getCities、getAreas都返回一個Promise物件,本來深度回撥的程式碼,就變成了序列的程式碼。(請大家避免如下書寫有關Promise的程式碼)
getProvinces().then(result => {
console.log('省級行政區域的資訊為:' + result)
getCities().then(result => {
console.log('地級行政區域的資訊為:' + result)
getAreas().then(result => {
console.log('縣級行政區域的資訊為:' + result)
})
})
})
雖然Promise解決了深度回撥的問題,但是卻引入了大量無用的程式碼,你會寫很多then,程式碼也變得很難看了。
於是,ES7中加入了async和await這對關鍵字。
await 命令只能用在async函式之中。async函式是基於Generator函式的實現,由於我們直接跳過了generator,這兒必須得提一個概念叫做協程,才便於大家對async函式的理解。就是函式在執行的時候,如果遇到一些條件,它會將執行條件交給另外的函式,等另外的函式執行完成之後,再將執行權力交回繼續執行。(純屬個人理解,如果紕漏,盡情指出)。
畫個圖就是如下:
async function asyncGetFileInfo() { var fileInfo await getFileInfo(); return fileInfo; }
這段程式碼的意思正如上圖所示。async函式返回的是一個Promise,我們這樣來理解吧,裡面既然是非同步的東西,肯定有些東西要等一會兒才可以得到吧。而await(await緊跟一個Promise)直接是取得非同步的結果,我們可以不用再呼叫then。
然後 剛才那麼多Promise組成的獲得行政區域的資訊的方法可以簡化成如下程式碼:
async function getDistrictInfo() {
var province = await getProvinces();
var city = await getCities();
var area = await getAreas();
return `${province}省(市,自治區)${city}市(區)${area}縣市區旗`
}
getDistrictInfo().then(result => { console.log(result); });
由於ES7太新,瀏覽器支援的不太好(nodejs請放心使用),我們需要babel進行轉碼。
npm install --save-dev babel-preset-latest