从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()); }); };