《Go 后端开发者学 TypeScript:从零理解 async、await 与 Promise》

你先记住一句话:

async 表示异步函数,await 表示等待异步操作的结果。

一、先看普通函数(没有 async)

你熟悉的 Go 代码:

go 复制代码
func add(a int, b int) int {
    return a + b
}

func main() {
    result := add(1, 2)
    fmt.Println(result) // 3
}

TypeScript 写法:

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。

typescript 复制代码
async function add(a: number, b: number): Promise<number> {
    return a + b;
}

const result = add(1, 2);
console.log(result);

这时候结果不是 3,而是:

javascript 复制代码
Promise { 3 }

为什么?

因为 async 有一个非常重要的规则:

加上 async 后,函数一定返回 Promise 对象,而不是直接返回普通值。

你可以暂时把 Promise<number> 理解为:

一个承诺:这个操作最终会得到一个 number 类型的结果。

比如:

javascript 复制代码
// 普通函数:直接返回数字
function add1(): number {
    return 3;
}

// async 函数:返回 Promise<number>
async function add2(): Promise<number> {
    return 3;
}

注意:add2 虽然写的是 return 3,但调用它得到的是 Promise<number>。

三、那么如何获取 Promise 里面的值?

这就需要 await。

javascript 复制代码
async function add(): Promise<number> {
    return 3;
}

async function main() {
    const result = await add();

    console.log(result); // 3
}

main();

重点看:

csharp 复制代码
const result = await add();

这里的 await 表示:

等待 add() 返回的 Promise 完成,然后取出里面的结果。

所以:

csharp 复制代码
const a = add();       // a 是 Promise<number>

const b = await add(); // b 是 number(需要在 async 函数内)

这就是 await 最核心的用途。

四、再举一个有等待时间的例子

假设你要模拟一个耗时 2 秒的数据库查询。

先不用理解 Promise 的内部实现,只需要知道下面的 sleep 能实现等待。

javascript 复制代码
function sleep(ms: number): Promise<void> {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

然后看主函数:

javascript 复制代码
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();

运行结果:

markdown 复制代码
1. 开始
开始查询数据库

(等待 2 秒)

数据库查询结束
2. 查询结果: 张三
3. 结束

你可以把它和 Go 的同步代码对比:

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?直接同步执行不行吗?

来看一个更重要的例子。

假设有两个耗时操作:

csharp 复制代码
async function task1(): Promise<string> {
    await sleep(2000);
    return "任务1完成";
}

async function task2(): Promise<string> {
    await sleep(2000);
    return "任务2完成";
}

情况 A:串行执行

ini 复制代码
async function main() {
    const a = await task1();
    const b = await task2();

    console.log(a, b);
}

main();

串行执行,总耗时约 4 秒

情况 B:并发执行

ini 复制代码
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 同时处理多个任务,在效果上有点类似,但底层机制不同。

注:

我们换一个有耗时操作的例子:

typescript 复制代码
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);

这时候输出大致是:

javascript 复制代码
Promise { <pending> }

这里的 <pending> 表示 Promise 还没完成,并不是 result 为空。

六、最后给你一个简单的理解方式

TypeScript 你可以怎么理解
function 普通函数
async function 返回 Promise 的函数
Promise<number> 未来可能得到一个 number 的异步结果
await 等待 Promise 完成并取出结果
Promise.all() 并发等待多个异步操作完成

这里最容易误解的一点:async 不是 Go 的 go 关键字。

在 Go 中:

scss 复制代码
go task1()

会创建一个新的 goroutine 来运行函数。

而 TypeScript:

csharp 复制代码
async function task1() {
    // ...
}

只是声明了一个返回 Promise 的异步函数,并没有自动创建线程,也没有自动让函数并行执行。

我建议你现在先理解一个问题:

javascript 复制代码
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 了。

相关推荐
Penge66633 分钟前
typescript 中const用法
javascript
程序员大阳11 小时前
HTML+CSS+JS对话式实战(3)-活动管理页实现查询、新增、删除API后端接口
javascript·css·html·实战·删除·查询·新增
炫酷的大高个12 小时前
6 亿播放的闪身步,我用前端算出 15 倍重心差
前端·javascript
林小帅12 小时前
【笔记】Prisma v7 + SQLite TS2305 及连锁 TS7006 问题
前端·javascript·后端
Dumbness12 小时前
订阅消息弹窗必须在用户点击里调:联调实验室里 timing 和 Mock 支付通知踩的坑
javascript·uni-app
黄连木笛13 小时前
不改一行 Postman 源码,把它汉化了:Electron preload 注入 + fetch 拦截实战
javascript·electron
叼烟扛炮14 小时前
[LangChain] 学习笔记(03):打破失忆症——对话机制与上下文管理
java·前端·javascript·笔记·学习·langchain
卋罖75015 小时前
Razor 视图 + JavaScript + Vue/iView 组件实现的表格自定义列
javascript·vue·iview·razor视图
系统集成-鹰翔1 天前
ERP图片改名后仍命中识别缓存:缓存键、十分钟到期与调用计数
javascript·经验分享·后端