跳转至

TypeScript中的 async 的用法

typescript 中,异步函数 async 是一种特殊类型的函数,它可以返回一个 Promise 对象。异步函数使用 async 关键字声明,并使用 await 关键字等待 Promise 对象的完成。

下面详细记录一下 typescript 中的异步函数用法

什么是异步函数?

在 ts 中,如果使用 async function 定义一个函数,那么这个函数就是异步函数,这点和 python 很像

1
2
3
4
5
6
7
function normal() {
  return 123;
}

async function asyncFn() {
  return 123;
}

什么是 Promise

Promise 是一个用于**处理异步操作的对象**,表示一个“未来才会有结果的值”。它有三种状态:

状态 描述
pending 等待中(未完成)
fulfilled 已成功完成
rejected 已失败

对于一个耗时的操作,如网络请求,本地 IO 操作,可以不阻塞整个进程

定义一个返回 Promise 对象的函数

async function asyncFn(r:boolean=true): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        if(r){
            resolve('Async Function Result');
        }else{
            reject('Error occurred in Async Function');
        }  
    }, 1000);
  });
}

一般有两类结果

  1. 成功使用 resolve(xxx) 返回
  2. 失败使用 reject(xxx) 返回,这个 reject 的效果相当于抛了一个异常

也可以直接返回数据,如

1
2
3
async function asyncFn() {
  return 123;
}

这种看似返回了 123, 但其实是返回的是 Promise

1
2
3
4
5
6
async function test() {
    return 123
}

const result = test();
console.log(result);

上面代码输出Promise { 123 }

普通函数也可以返回 Promise 对象

一个普通的 function 函数,也是可以返回一个 Promise 对象的

1
2
3
4
5
6
7
8
function test2() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(123)
        }, 1000);
    }
    );
}

如何调用 async 函数?

如果直接调用一个异步函数,无论是 async function 定义的,还是普通的 function 函数,但是返回的是 Promise 对象,都将会得到一个 Promise { <pending> }

async function asyncFn(r:boolean=true): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        if(r){
            resolve('Async Function Result');
        }else{
            reject('Error occurred in Async Function');
        }  
    }, 1000);
  });
}

async function test() {
    return 123
}

function test2() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(123)
        }, 1000);
    }
    );
}

async function main() {
    const t1 = asyncFn()
    const t2 = test()
    const t3 = test2()
    console.log('t1', t1)
    console.log('t2', t2)
    console.log('t3', t3)
}

main();

上面的输出为

1
2
3
t1 Promise { <pending> }
t2 Promise { 123 }
t3 Promise { <pending> }

并不能正常的得到函数运行的结果

如何获得异步的执行结果呢? 有以下几种方式

1、使用 await

使用 await

1
2
3
4
5
6
7
8
async function main() {
    const t1 = await asyncFn()
    const t2 = await test()
    const t3 = await test2()
    console.log('t1', t1)
    console.log('t2', t2)
    console.log('t3', t3)
}

await 需要在 async function 函数中

使用 await 方式调用异步函数时,如果 Promise 返回的是 reject,则会报错,相当于其他语言里的 exception,所以经常配合 try 一起使用

async function asyncFn(r:boolean=true): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        if(r){
            resolve('Async Function Result');
        }else{
            reject('Error occurred in Async Function');
        }  
    }, 1000);
  });
}

async function main() {
    try{
        const r = await asyncFn(false);
        console.log(r);
    }catch(e){
        console.error(e);
    }

}

main()

2、使用 .then .catch

这个是传统的写法

async function main() {
    asyncFn(false).then(result=>{
        console.log('Result:', result);
    }).catch(error=>{
        console.error('Caught Error:', error);
    });
        // 下面的代码并不需要等待上面的代码执行结束再执行
    test2().then(result=>{
        console.log('Test2 Result:', result);
    });  
}

使用 then 的方式,可以不必写在 async 函数里。

3、使用一个匿名的 async 调用

因为使用 await 需要在 async 函数中调用,所以这会引出一系列的问题,将原本不是 async 的函数改为 async ,那么整个函数调用链都需要修改,下面这种提供了一中匿名调用,依然使用 await ,但是不用写在 async 函数里

在不能使用 await 的地方(比如普通函数或全局作用域),通过创建一个临时 async 函数来使用 await

function main() {
    (async()=>{
        try{
            const res1 = await asyncFn(false);
            console.log(res1)
        }catch(err){
            console.error(err)
        }   
    })();    
}

main();

无论那种方式,其实都是对于 Promise 对象结果的获取