从C#到TypeScript - async await

从C#到TypeScript - async await

上两篇分别说了PromiseGenerator,基础已经打好,现在可以开始讲async await了。 async await是ES7的议案,TypeScript在1.7版本开始支持async await编译到ES6,并在2.1版本支持编译到ES5和ES3,算是全面支持了。

async await 用法

和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.allPromise.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返回Promise状态

一个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原理

前篇有说过async await其实是Generator的语法糖。 除了*换成asyncyield换成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());
    });
};

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android源码框架分析

Android后台杀死系列之三:LowMemoryKiller原理(4.3-6.0)

本篇是Android后台杀死系列的第三篇,前面两篇已经对后台杀死注意事项,杀死恢复机制做了分析,本篇主要讲解的是Android后台杀死原理。相对于后台杀死恢复,...

1245
来自专栏个人随笔

JFinal 3.3 学习 -- JFinalConfig (配置web项目)

4365
来自专栏尾尾部落

[剑指offer] 复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中...

763
来自专栏fixzd

redis系列:哨兵

Sentinel(哨兵)是Redis 的高可用性解决方案:通过哨兵可以创建一个当主服务器出现故障时自动将从服务器升级为主服务器的一个分布式系统。解决了主从复制出...

1614
来自专栏一名叫大蕉的程序员

简易但不简单的配置中心No.79

嘛小伙伴们都问我我是怎么抽那么多时间来看书的,其实说难也不难说简单其实也不简单,就是提高效率和挤时间嘛。你要相信在一天中,每个时间都有它自己应该待的位置,做好工...

2009
来自专栏张戈的专栏

修改Apache的超时设置,解决长连接请求超时问题

某日,组内后台开发找到我,问我们的 WEB 服务器超时设置是多少。他反馈的问题是,有一个 VLAN 切换任务 cgi 接口经常返回 504 网关超时错误,要我分...

5718
来自专栏Android 研究

APK安装流程详解1——有关"安装ing"的实体类概述

该类包含了从AndroidManifest.xml文件中收集的所有信息。 PackageInfo.java源码地址 通过源码我们知道PackageInfo是...

982
来自专栏Java Edge

Redis实践(八)-Sentinal12 主从复制高可用?3 Redis Sentinel 架构4 安装与配置5 安装与演示6 客户端11 三个定时任务12 主观下线和客观下线13 领导者选举14

由于Redis Sentinel只会对主节点进行故障转移,对从节点采取主观的下线,所以需要自定义一个客户端来监控对应的事件

811
来自专栏一个会写诗的程序员的博客

第13章 Kotlin 集成 SpringBoot 服务端开发(2)

其中,ON DUPLICATE KEY UPDATE 这句表明当遇到重复的键值的时候,执行更新 gmt_modified = now() 的操作。这里nativ...

741
来自专栏魂祭心

原 荐 NEO VM原理及其实现

3918

扫码关注云+社区