async是es6提出的一種新的異步語法. 一開始es爲了解決異步,使用的是promise, 但看到滿屏的then以後,就感受本身傻逼了. 後來提出了generator, 在底層實現了一個異步的模式, 但須要手動執行. 關於如何使用generator,能夠參考,how to use generator. 本文這裏,不探討怎麼使用generato. 而是,若是使用generator和promise 構造出async的表達.es6
通常異步的寫法就是,傳回調嘛,好比:ajax
var ajax = function(url,cb){ // send url // get res ... cb(JSON.parse(result)) }
這樣,應該最容易寫成callback hell. 而後咱們引入: generatorexpress
function *main() { var result1 = yield ajax( "http://some.url.1" ); var data = JSON.parse( result1 ); var result2 = yield ajax( "http://some.url.2?id=" + data.id ); var resp = JSON.parse( result2 ); } var async = main(); async.next(); function ajax(url){ // send url async.next(res); }
僞代碼的格式如上所述. 這裏,須要主意一個點. 若是,你沒有在next()中傳入res,like async.next()
. 那麼,裏面result1和result2得到的結果就是undefined.
上面就是基本的generator異步. 那若是使用generator來模擬async呢?
這估計得解釋一下async出現的緣由promise
根據上面的解析,咱們能夠了解到, 使用next 執行語句時, 只能執行yield後面的表達式. 這樣形成的結果就是,不能parallel異步呀. 這樣限制性仍是很大的。因此,爲了解決這個問題,使用到es6提出的Promise對象來進行補充.
這裏,增長一個限定規則,即,ajax拉取返回的必須是一個promise對象.babel
function ajax(url){ return new Promise(function(res,rej){ send(url,function(result){ res(result) }) }) }
咱們再補充一下,若是使用generator來對promise進行tricky異步
function runGenerator(g) { var it = g(), ret; (function iterate(val){ ret = it.next( val ); if (!ret.done) { // 檢查是否已經then完成 if ("then" in ret.value) { // 這一句很關鍵 ret.value.then( iterate ); } else { // 同步回調的trick setTimeout( function(){ iterate( ret.value ); }, 0 ); } } })(); }
OK, 這樣, 咱們就能夠在async裏面,使用同步的寫法,來表明異步的操做了.async
runGenerator(function* (){ var result = yield new Promise(function(res,rej){ setTimeout(function(){ res('ok'); },1000) }); })
因爲這裏要求的是使用promise, 那麼,咱們使用Promise.all([xx,xx]) 也是合情合理的. 這樣就能夠完美的解決掉--並行異步發送。url
runGenerator(function* (){ yield Promise.all([ajax('http://villainhr.com'),ajax('http://villainhr.com')]) })
對比與,使用async的結構:code
(async function(){ await Promise.all([ajax('http://villainhr.com'),ajax('http://villainhr.com')]); })();
是否是感受一毛同樣呢? 不過在實際上操做中, async 還必須對new Promise進行兼容處理. 若是其餘人直接傳入一個expression, 你也必須保證他是可行的.
在babel中,講的其實也是這樣一個邏輯:orm
// In async function foo() { await bar(); } // Out var _asyncToGenerator = function (fn) { ... }; var foo = _asyncToGenerator(function* () { yield bar(); });
具體參考: babel es6 轉碼