從C#到TypeScript - 高級類型typescript
從C#到TypeScript - 變量promise
從C#到TypeScript - 類async
上兩篇分別說了Promise
和Generator
,基礎已經打好,如今能夠開始講async await
了。
async await
是ES7的議案,TypeScript在1.7版本開始支持async await
編譯到ES6,並在2.1版本支持編譯到ES5和ES3,算是全面支持了。
和C#裏的十分類似,看個例子:
function delay(): Promise<void>{ return new Promise<void>((resolve, reject)=>{setTimeout(()=>resolve(), 2000)}); } async function run(){ console.info('start'); await delay(); console.info('finish'); } run(); console.info('run');
上面代碼執行的結果是執行完run()
後當即返回一個Promise
,遇到await
跳出函數,繼續往下走,因此先輸出start
,再緊接着輸出run
,過了2秒後再輸出finish
。
能夠看到run
函數,function前面多了個async
(若是是class裏的方法,則是在函數名前),delay()前面多了個await
,表示的意思很明顯,就是在二者之間等待2秒。
run
函數返回的也是一個Promise
對象,後面能夠接then
來作後續操做。
await
必需要在async
塊中,await的對象能夠是Promise
對象也能夠不是,不是的話會自動轉爲已經resolved的Promise對象。
另外,await
在代碼塊中是按順序執行的,前面wait完後再會走下一步,若是須要並行執行,能夠和Promise
同樣,用Promise.all
或Promise.race
來達到目的。
async function run1(){ await delay(); console.info('run1'); } async function run2(){ await delay(); console.info('run2'); } async function run3(){ await delay(); console.info('run3'); } Promise.all([run1(), run2(), run3()]);
上面代碼會在兩秒後幾乎同時輸出run1, run2, run3。
一個async函數中能夠有N個await,async函數返回的Promise則是由函數裏全部await一塊兒決定,只有全部await的狀態都resolved以後,async函數纔算真正完成,返回的Promise的狀態也變爲resolved。
固然若是中間return了或者出了異常仍是會中斷的。
async function run(){ console.info('start'); await delay(); console.info('time 1'); await delay(); console.info('time 2'); return; //下面固然就不會執行了 await delay(); console.info('time 3'); }
run
的狀態在time 2輸出後return就轉爲resolved
了。
當這裏出異常時,async函數會中斷並把異常返回到Promise
裏的reject
函數。
async function run(){ await Promise.reject('error'); // 這裏出異常 console.info('continue'); // 不會執行到這裏 await delay(); }
以前有提到Promise
的異常能夠在後面用catch
來捕獲,async await
也同樣。
向上面的例子,可能有須要把整個函數即便出異常也要執行完,就能夠這樣作:
async function run(){ await Promise.reject('error').catch(e=>console.info(e)); console.info('continue'); // 繼續往下執行 await delay(); } let g = run(); //這裏的g也是成功的,由於異常已經被處理掉
若是是多個異常須要處理,能夠用try...catch
async function run(){ try{ await Promise.reject('error1'); await Promise.reject('error2'); } catch(e){ console.info(e); } console.info('continue'); // 繼續往下執行 await delay(); }
前篇有說過async await
實際上是Generator
的語法糖。
除了*
換成async
, yield
換成await
以外,最主要是async await
內置了執行器,不用像Generator
用那樣next()
一直往下執行。
其實也就是async await
內部作了co模塊作的事。
先來看看async await在TypeScript翻譯後的結果:
async function run(){ await delay(); console.info('run'); } //翻譯成 function run() { return __awaiter(this, void 0, void 0, function* () { yield delay(); console.info('run'); }); }
能夠注意到其實仍是用__await()
包了一個Generator
函數,__await()
的實現其實和上篇的co模塊的實現基本一致:
var __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) { return new(P || (P = Promise))(function(resolve, reject) { function fulfilled(value) { // 也是fulfilled,resolved的別名 try { step(generator.next(value)); // 關鍵仍是這個step,裏面遞歸調用fulfilled } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function(resolve) { //P是Promise的類型別名 resolve(result.value); }).then(fulfilled, rejected); // 沒有done的話繼續fulfilled } step((generator = generator.apply(thisArg, _arguments)).next()); }); };