async / await是ES7的重要特性之一,也是目前社區里公認的優秀異步解決方案。目前,async / await這個特性已經是stage 3的建議,可以看看TC39的進度,本篇文章將分享async / await是如何工作的,閱讀本文前,希望你具備Promise、generator、yield等ES6的相關知識。
在詳細介紹async / await之前,先回顧下目前在ES6中比較好的異步處理辦法。下面的例子中數據請求用Node.js中的request模塊,數據接口采用Github v3 api文檔提供的repo代碼倉庫詳情API作為例子演示。
Promise對異步的處理
雖然Node.js的異步IO帶來了對高并發的良好支持,同時也讓“回調”成為災難,很容易造成回調地獄。傳統的方式比如使用具名函數,雖然可以減少嵌套的層數,讓代碼看起來比較清晰。但是會造成比較差的編碼和調試體驗,你需要經常使用用ctrl + f去尋找某個具名函數的定義,這使得IDE窗口經常上下來回跳動。使用Promise之后,可以很好的減少嵌套的層數。另外Promise的實現采用了狀態機,在函數里面可以很好的通過resolve和reject進行流程控制,你可以按照順序鏈式的去執行一系列代碼邏輯了。下面是使用Promise的一個例子:
const request = require('request');// 請求的url和headerconst options = { url: 'https://api.github.com/repos/cpselvis/zhihu-crawler', headers: { 'User-Agent': 'request' }};// 獲取倉庫信息const getRepoData = () => { return new Promise((resolve, reject) => { request(options, (err, res, body) => { if (err) { reject(err); } resolve(body); }); });};getRepoData() .then((result) => console.log(result);) .catch((reason) => console.error(reason););// 此處如果是多個Promise順序執行的話,如下:// 每個then里面去執行下一個promise// getRepoData()// .then((value2) => {return promise2})// .then((value3) => {return promise3})// .then((x) => console.log(x))不過Promise仍然存在缺陷,它只是減少了嵌套,并不能完全消除嵌套。舉個例子,對于多個promise串行執行的情況,第一個promise的邏輯執行完之后,我們需要在它的then函數里面去執行第二個promise,這個時候會產生一層嵌套。另外,采用Promise的代碼看起來依然是異步的,如果寫的代碼如果能夠變成同步該多好??!
Generator對異步的處理
談到generator,你應該不會對它感到陌生。在Node.js中對于回調的處理,我們經常用的TJ / Co就是使用generator結合promise來實現的,co是coroutine的簡稱,借鑒于python、lua等語言中的協程。它可以將異步的代碼邏輯寫成同步的方式,這使得代碼的閱讀和組織變得更加清晰,也便于調試。
const co = require('co');const request = require('request');const options = { url: 'https://api.github.com/repos/cpselvis/zhihu-crawler', headers: { 'User-Agent': 'request' }};// yield后面是一個生成器 generatorconst getRepoData = function* () { return new Promise((resolve, reject) => { request(options, (err, res, body) => { if (err) { reject(err); } resolve(body); }); });};co(function* () { const result = yield getRepoData; // ... 如果有多個異步流程,可以放在這里,比如 // const r1 = yield getR1; // const r2 = yield getR2; // const r3 = yield getR3; // 每個yield相當于暫停,執行yield之后會等待它后面的generator返回值之后再執行后面其它的yield邏輯。 return result;}).then(function (value) { console.log(value);}, function (err) { console.error(err.stack);});
新聞熱點
疑難解答
圖片精選