在 TypeScript 项目开发中,异步编程是业务开发的核心基础。从回调嵌套的弊端,到 Promise 规范化异步流程,再到 async/await 语法糖简化写法,结合 TS 函数特性、泛型能力,能够写出类型安全、结构清晰、易于维护的异步代码。本文重点讲解 Promise、async/await 核心用法,以及它们与普通函数、泛型的联合使用场景。

一、初识 Promise

Promise 是处理异步操作的原生方案,拥有 pending、fulfilled、rejected 三种状态,支持链式调用,从根本上解决回调地狱问题。

1. 基础 Promise 封装

const MAX_DELAY_TIME = 5000;
const REQUEST_SUCCESS = 200;

function Create_Async_Task<T>(data: T, delay: number) {
    return new Promise<T>((resolve, reject) => {
        setTimeout(() => {
            if (delay < MAX_DELAY_TIME) {
                resolve(data);
            }
            else {
                reject("异步任务执行超时");
            }
        }, delay);
    });
}

2. Promise 链式调用

function Get_User_Base_Info() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({ id: 1, nickName: "TypeScript" });
        }, 1000);
    });
}

Get_User_Base_Info()
.then(res => {
    console.log("用户基础信息", res);
    return Create_Async_Task(REQUEST_SUCCESS, 1500);
})
.then(code => {
    console.log("请求状态码", code);
})
.catch(err => {
    console.log("任务异常", err);
});

二、async /await 语法使用

async/await 是基于 Promise 的语法糖,允许以同步代码的书写方式编写异步逻辑,代码可读性大幅提升。

1. 基础使用方式

async function Exec_Simple_Async() {
    try {
        const result = await Create_Async_Task("异步任务执行完成", 2000);
        console.log("执行结果:", result);
    }
    catch (error) {
        console.log("捕获异常:", error);
    }
}

Exec_Simple_Async();

2. 循环中配合 await

const TASK_DELAY_LIST = [1000, 1800, 2500];

async function Batch_Exec_Task() {
    for (const item of TASK_DELAY_LIST) {
        if (item > 1500) {
            const res = await Create_Async_Task(`延时 ${item}ms 任务`, item);
            console.log(res);
        }
    }
}

Batch_Exec_Task();

三、Promise 结合 TS 泛型联合使用

泛型可以对 Promise 返回值做类型约束,实现类型自动推导,规避类型断言带来的隐患,是 TS 异步开发的核心用法。

1. 通用泛型请求函数封装

function Http_Request<T>(url: string, params: T): Promise<T> {
    return new Promise<T>((resolve) => {
        setTimeout(() => {
            console.log("请求接口地址:", url);
            resolve(params);
        }, 800);
    });
}

interface User_Entity {
    id: number;
    username: string;
    age: number;
}

async function Load_User_Info() {
    const userInfo = await Http_Request<User_Entity>("/api/user/info", {
        id: 1001,
        username: "AsyncDemo",
        age: 22
    });
    console.log("用户名:", userInfo.username);
}

Load_User_Info();

四、Promise 静态方法常用场景

1. Promise.all 并发执行多个异步

async function Parallel_Request() {
    const task1 = Create_Async_Task("接口返回数据1", 1200);
    const task2 = Create_Async_Task("接口返回数据2", 1000);
    const task3 = Create_Async_Task("接口返回数据3", 1500);

    const resultArr = await Promise.all([task1, task2, task3]);
    console.log("并发请求全部结果:", resultArr);
}

Parallel_Request();

2. Promise.race 异步竞速场景

async function Race_Task_Demo() {
    const slowTask = Create_Async_Task("慢速接口响应", 3000);
    const fastTask = Create_Async_Task("快速接口响应", 1000);

    const raceResult = await Promise.race([slowTask, fastTask]);
    console.log("最先响应的任务:", raceResult);
}

Race_Task_Demo();

五、异步函数与普通函数组合调用

实际业务中,经常需要同步工具函数与异步逻辑配合使用。

function Check_Delay_Valid(delay: number): boolean {
    if (delay > MAX_DELAY_TIME) {
        return false;
    }
    return true;
}

async function Business_Logic_Exec(delay: number) {
    const isValid = Check_Delay_Valid(delay);
    if (isValid != false) {
        const res = await Create_Async_Task("业务逻辑执行成功", delay);
        console.log(res);
    }
    else {
        console.log("延时超出限制,拒绝执行");
    }
}

Business_Logic_Exec(3000);
Business_Logic_Exec(6000);

六、开发实践总结

  1. 统一使用 Promise 封装所有异步操作,配合 TS 泛型固定返回类型,保证类型安全;
  2. 业务代码优先采用 async/await 替代原生 Promise 链式调用,逻辑更直观;
  3. 使用 await 时必须搭配 try/catch 捕获异常,防止异步错误阻塞程序;
  4. 通用异步、请求逻辑抽离为独立泛型函数,提高代码复用性;
  5. 有序异步场景使用 for...of 配合 await,避免普通 for 循环异步执行顺序错乱。

更多推荐