你先记住一句话:
async 表示异步函数,await 表示等待异步操作的结果。
一、先看普通函数(没有 async)
你熟悉的 Go 代码:
func add(a int, b int) int {
return a + b
}
func main() {
result := add(1, 2)
fmt.Println(result) // 3
}
TypeScript 写法:
function add(a: number, b: number): number {
return a + b;
}
const result = add(1, 2);
console.log(result); // 3
这里和 Go 基本一样:
a: number:参数 a 是数字。: number:函数返回数字。return a + b:返回计算结果。
add(1, 2) 直接返回 3。
二、加上 async 会发生什么?
现在只做一个修改,在函数前面加 async。
async function add(a: number, b: number): Promise<number> {
return a + b;
}
const result = add(1, 2);
console.log(result);
这时候结果不是 3,而是:
Promise { 3 }
为什么?
因为 async 有一个非常重要的规则:
加上 async 后,函数一定返回 Promise 对象,而不是直接返回普通值。
你可以暂时把 Promise<number> 理解为:
一个承诺:这个操作最终会得到一个 number 类型的结果。
比如:
// 普通函数:直接返回数字
function add1(): number {
return 3;
}
// async 函数:返回 Promise<number>
async function add2(): Promise<number> {
return 3;
}
注意:add2 虽然写的是 return 3,但调用它得到的是 Promise<number>。
三、那么如何获取 Promise 里面的值?
这就需要 await。
async function add(): Promise<number> {
return 3;
}
async function main() {
const result = await add();
console.log(result); // 3
}
main();
重点看:
const result = await add();
这里的 await 表示:
等待 add() 返回的 Promise 完成,然后取出里面的结果。
所以:
const a = add(); // a 是 Promise<number>
const b = await add(); // b 是 number(需要在 async 函数内)
这就是 await 最核心的用途。
四、再举一个有等待时间的例子
假设你要模拟一个耗时 2 秒的数据库查询。
先不用理解 Promise 的内部实现,只需要知道下面的 sleep 能实现等待。
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
然后看主函数:
async function queryDB(): Promise<string> {
console.log("开始查询数据库");
await sleep(2000);
console.log("数据库查询结束");
return "张三";
}
async function main() {
console.log("1. 开始");
const name = await queryDB();
console.log("2. 查询结果:", name);
console.log("3. 结束");
}
main();
运行结果:
1. 开始
开始查询数据库
(等待 2 秒)
数据库查询结束
2. 查询结果: 张三
3. 结束
你可以把它和 Go 的同步代码对比:
func queryDB() string {
fmt.Println("开始查询数据库")
time.Sleep(2 * time.Second)
fmt.Println("数据库查询结束")
return "张三"
}
func main() {
fmt.Println("1. 开始")
name := queryDB()
fmt.Println("2. 查询结果:", name)
fmt.Println("3. 结束")
}
两段代码的执行顺序很像。
但有一个本质区别:
- Go 的
time.Sleep会阻塞当前 goroutine。 - TypeScript 的
await sleep()会暂停当前异步函数的后续执行,但不会阻塞整个 JavaScript 线程。
五、为什么需要 async?直接同步执行不行吗?
来看一个更重要的例子。
假设有两个耗时操作:
async function task1(): Promise<string> {
await sleep(2000);
return "任务1完成";
}
async function task2(): Promise<string> {
await sleep(2000);
return "任务2完成";
}
情况 A:串行执行
async function main() {
const a = await task1();
const b = await task2();
console.log(a, b);
}
main();
串行执行,总耗时约 4 秒
情况 B:并发执行
async function main() {
const p1 = task1();
const p2 = task2();
const a = await p1;
const b = await p2;
console.log(a, b);
}
main();
并发执行,总耗时约 2 秒
为什么第二种更快?
因为调用 task1() 时,遇到内部的 await sleep(),它会暂停任务1的后续执行,并返回 Promise。
程序可以继续调用 task2(),让两个异步等待过程重叠。
这和 Go 里面使用 goroutine 同时处理多个任务,在效果上有点类似,但底层机制不同。
注:
我们换一个有耗时操作的例子:
async function add(a: number, b: number): Promise<number> {
await new Promise(resolve => setTimeout(resolve, 2000));
return a + b;
}
const result = add(1, 2);
console.log(result);
这时候输出大致是:
Promise { <pending> }
这里的 <pending> 表示 Promise 还没完成,并不是 result 为空。
六、最后给你一个简单的理解方式
| TypeScript | 你可以怎么理解 |
|---|---|
function | 普通函数 |
async function | 返回 Promise 的函数 |
Promise<number> | 未来可能得到一个 number 的异步结果 |
await | 等待 Promise 完成并取出结果 |
Promise.all() | 并发等待多个异步操作完成 |
这里最容易误解的一点:async 不是 Go 的 go 关键字。
在 Go 中:
go task1()
会创建一个新的 goroutine 来运行函数。
而 TypeScript:
async function task1() {
// ...
}
只是声明了一个返回 Promise 的异步函数,并没有自动创建线程,也没有自动让函数并行执行。
我建议你现在先理解一个问题:
async function getNumber(): Promise<number> {
return 100;
}
async function main() {
const a = getNumber();
const b = await getNumber();
console.log(a);
console.log(b);
}
你能看出这里的 a 和 b 分别是什么类型、打印出来有什么区别,就算初步理解 async/await 了。