跳转到内容

同步 / 异步

我个人认为 TypeScript 最大的优势之一是它在处理异步操作时的便捷和易上手。在这个部分中我将会详细介绍这两个非常有用的东西。首先我们要知道什么是同步和异步操作。

同步操作

同步操作 是指代码按照顺序执行,每一行代码都会等待上一行代码执行完毕后再执行。这种操作方式是最常见的,也是最容易理解的。其实就是我们平时写的代码,一行一行有序执行。这里就不再赘述。

异步操作

异步操作 是指代码不按照顺序执行,可以让多个操作同时进行。这样的操作可以避免程序进行等待。

一个简单的例子是当我们需要获取 小明 小红 小刚 的手机号时,我们需要分别在电话本中查找他们的号码。如果是同步操作,我们需要先找到小明的号码,再找到小红的号码,最后找到小刚的号码。这样的操作是非常耗时的。但是如果是异步操作,我们可以同时查找他们的号码,这样就会节省很多时间。

什么时候使用异步操作

异步操作固然节省了很多时间,但是切记,在数据有依赖关系的情况下,我们必须使用同步操作。比如我们需要获取小明的手机号,然后根据小明的手机号获取小明的地址。这时候我们就必须使用同步操作,因为小明的地址依赖于小明的手机号。

异步操作的实现

为了实现异步操作,我们需要介绍几个概念:asyncawait 以及 Promise。这三个概念是 TypeScript 中处理异步操作的核心。

async

async 是一个修饰符,用来表示一个函数是异步的。举个例子,我们有一个函数 getPhone,这个函数是异步的,我们可以这样定义这个函数:

async function getPhone() {
// 一些需要耗费时间的操作
}
getPhone();
console.log('这一行会在调用 getPhone 后立刻执行');

在这个例子中,async 修饰符告诉 TypeScript 这个函数是异步执行的,当我们调用这个函数时,系统会在后台执行这个 getPhone 函数,然后不会等待 getPhone 函数执行完毕就会执行下一行代码。

Promise

现在你可能发现了一个问题,如果我们不执行 getPhone 函数,我们怎么知道这个函数会返回什么类型的值呢?在这种情况下,传统的 : number 类型注解就不再适用了。这时候我们就需要 Promise

Promise 是一个对象,用来表示一个异步操作的最终完成或者失败。我们可以简单理解为 Promise 是一个空盒子,你可以通过轮廓知道这个盒子里面有什么类型的东西,但是这个轮廓里有可能是空的。

听起来有点绕?没关系,我们来修改一下上面的例子:

async function getPhone(): Promise<string> {
// 一些需要耗费时间的操作
return '123456789';
}

现在,我们给 getPhone 函数添加了一个返回类型 Promise<string>,表示这个函数会返回一个 string 类型的值。

await

当然,有时候我们的异步操作是有依赖关系的,这时候我们就需要使用 await 关键字。await 关键字可以让 TypeScript 等待一个异步操作的结果。换句话说,await 可以把一个异步操作变成一个同步操作。在这里,我们新增了一个函数 getAddress,这个函数需要输入一个电话号码,然后返回一个地址:

async function getAddress(phone: string): Promise<string> {
// 一些需要耗费时间的操作
return 'Shanghai';
}

现在我们可以使用 await 关键字来等待 getPhone 函数的返回值:

const phone = await getPhone();
const address = await getAddress(phone);
console.log(address); // 'Shanghai'

在这个例子中,我们先等待 getPhone 函数完整执行完毕,然后把它的结果存入 phone 变量中。接着我们再等待 getAddress 函数完整执行完毕,然后把它的结果存入 address 变量中。最后我们打印出 address 变量的值。