第9章 异步编程
本章定位:深入学习TypeScript的异步编程模型,包括Promise基础、async/await语法、错误处理、并发模式,以及与Python asyncio的对比。
9.1 Promise基础
Section titled “9.1 Promise基础”Promise是JavaScript/TypeScript中处理异步操作的对象,代表一个异步操作的最终结果(成功或失败)。
// Promise的三个状态// 1. Pending(待定)- 初始状态// 2. Fulfilled(已兑现)- 操作成功// 3. Rejected(已拒绝)- 操作失败创建Promise
Section titled “创建Promise”// 基本Promiseconst promise = new Promise<string>((resolve, reject) => { setTimeout(() => { resolve("Success!"); }, 1000);});
promise.then(result => { console.log(result); // "Success!"});
// 拒绝的Promiseconst failedPromise = new Promise<string>((resolve, reject) => { setTimeout(() => { reject(new Error("Failed!")); }, 1000);});
failedPromise.catch(error => { console.error(error.message); // "Failed!"});Python对比:
# Python asyncioimport asyncio
async def async_operation(): await asyncio.sleep(1) return "Success!"
async def main(): result = await async_operation() print(result)
asyncio.run(main())Promise状态转换
Section titled “Promise状态转换”// state: pending -> fulfilledconst successPromise = new Promise((resolve) => { resolve("done");});
// state: pending -> rejectedconst errorPromise = new Promise((_, reject) => { reject(new Error("error"));});
// 一旦Promise settled,状态不可变const promise = new Promise((resolve) => { resolve("first"); resolve("second"); // 被忽略});Promise链式调用
Section titled “Promise链式调用”// .then() 返回新的PromisefetchUser(1) .then(user => fetchUserPosts(user.id)) .then(posts => filterPublicPosts(posts)) .then(publicPosts => publicPosts.length) .then(count => console.log(`${count} public posts`)) .catch(error => console.error(error));Promise静态方法
Section titled “Promise静态方法”// Promise.all - 所有都成功才成功const promises = [ fetchUser(1), fetchUser(2), fetchUser(3)];const users = await Promise.all(promises);
// Promise.allSettled - 所有完成(不管成功失败)const results = await Promise.allSettled(promises);results.forEach((result, i) => { if (result.status === "fulfilled") { console.log(`User ${i}: ${result.value}`); } else { console.log(`User ${i}: ${result.reason}`); }});
// Promise.race - 最先完成的(成功或失败)const first = await Promise.race([ fetchFromServer1(), fetchFromServer2(), fetchFromServer3()]);
// Promise.any - 最先成功的(忽略失败)const any = await Promise.any([ fetchPrimary(), fetchBackup()]);9.2 async/await语法
Section titled “9.2 async/await语法”async/await是Promise的语法糖,让异步代码看起来像同步代码:
// async函数自动返回Promiseasync function fetchUser(id: number): Promise<User> { const response = await fetch(`/api/users/${id}`); return response.json();}
// 调用async函数fetchUser(1).then(user => console.log(user));Python对比:
import aiohttp
async def fetch_user(session: aiohttp.ClientSession, user_id: int) -> dict: async with session.get(f"/api/users/{user_id}") as response: return await response.json()
async def main(): user = await fetch_user(session, 1) print(user)await 表达式
Section titled “await 表达式”async function process() { try { const result = await someAsyncOperation(); console.log(result); } catch (error) { console.error(error); }}async 函数的返回类型
Section titled “async 函数的返回类型”// 显式返回Promiseasync function getNumber(): Promise<number> { return 42; // 自动包装为Promise}
// 隐式推断async function getString() { return "hello"; // 推断为 Promise<string>}
// void async函数async function logSomething() { console.log("logging");} // Promise<void>await 在循环中
Section titled “await 在循环中”// 顺序执行async function processAll(items: string[]) { for (const item of items) { const result = await processItem(item); console.log(result); }}
// 并行执行async function processAllParallel(items: string[]) { const promises = items.map(item => processItem(item)); const results = await Promise.all(promises); console.log(results);}
// 错误处理async function processWithErrors(items: string[]) { const results = await Promise.allSettled( items.map(item => processItem(item)) ); results.forEach((result, i) => { if (result.status === "fulfilled") { console.log(`Item ${i}: ${result.value}`); } else { console.error(`Item ${i} failed: ${result.reason}`); } });}9.3 错误处理:try/catch
Section titled “9.3 错误处理:try/catch”基本错误处理
Section titled “基本错误处理”async function fetchData(url: string) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const data = await response.json(); return data; } catch (error) { if (error instanceof TypeError) { console.error("Network error:", error); } else if (error instanceof Error) { console.error("Server error:", error.message); } throw error; // 重新抛出 }}async function main() { try { await riskyOperation(); } catch (error) { console.error("Operation failed:", error); // 错误可以被上层捕获 throw new Error("Wrapper", { cause: error }); }}
// 调用者try { await main();} catch (error) { console.error("Failed:", error);}finally 块
Section titled “finally 块”async function withCleanup() { let connection: Connection;
try { connection = await getConnection(); const result = await connection.query("SELECT * FROM users"); return result; } catch (error) { console.error("Query failed:", error); throw error; } finally { // 无论成功还是失败,都会执行 if (connection) { await connection.close(); } }}Python对比:
async def with_cleanup(): connection = None try: connection = await get_connection() result = await connection.query("SELECT * FROM users") return result except Exception as e: print(f"Query failed: {e}") raise finally: if connection: await connection.close()// 自定义错误类型class AppError extends Error { constructor( message: string, public code: string, public status: number = 500 ) { super(message); this.name = "AppError"; }}
// 使用async function fetchData(url: string) { try { const response = await fetch(url); if (response.status === 404) { throw new AppError("Not found", "NOT_FOUND", 404); } return response.json(); } catch (error) { if (error instanceof AppError) { console.error(`${error.code}: ${error.message}`); } throw error; }}9.4 Promise链式调用
Section titled “9.4 Promise链式调用”then/catch/finally
Section titled “then/catch/finally”fetchUser(1) .then(user => user.posts) .then(posts => posts.filter(p => p.public)) .then(publicPosts => publicPosts.length) .then(count => { console.log(`Found ${count} public posts`); }) .catch(error => { console.error("Failed:", error); }) .finally(() => { console.log("Operation complete"); });扁平化Promise链
Section titled “扁平化Promise链”// 避免嵌套doSomethingA() .then(resultA => { // 错误的嵌套方式 doSomethingB(resultA).then(resultB => { doSomethingC(resultB).then(resultC => { console.log(resultC); }); }); });
// 正确的扁平方式doSomethingA() .then(resultA => doSomethingB(resultA)) .then(resultB => doSomethingC(resultB)) .then(resultC => console.log(resultC));Promise.resolve 和 Promise.reject
Section titled “Promise.resolve 和 Promise.reject”// Promise.resolve - 创建已成功的Promiseconst resolved = Promise.resolve(42);resolved.then(v => console.log(v)); // 42
// Promise.reject - 创建已失败的Promiseconst rejected = Promise.reject(new Error("failed"));
// 转换同步值为Promiseasync function getUser() { const user = await Promise.resolve({ id: 1, name: "Alice" }); return user;}组合多个Promise
Section titled “组合多个Promise”// 顺序执行async function sequence(tasks: (() => Promise<void>)[]) { for (const task of tasks) { await task(); }}
// 并行执行async function parallel(tasks: (() => Promise<void>)[]) { await Promise.all(tasks.map(task => task()));}
// 限流async function limitedParallel(tasks: (() => Promise<void>)[], limit: number) { const chunks: (() => Promise<void>)[] = []; for (let i = 0; i < tasks.length; i += limit) { chunks.push(() => Promise.all(tasks.slice(i, i + limit))); } for (const chunk of chunks) { await chunk(); }}9.5 TypeScript并发模式
Section titled “9.5 TypeScript并发模式”async function sequential() { const a = await stepA(); // 等待A完成 const b = await stepB(); // 等待B完成 const c = await stepC(); // 等待C完成 return [a, b, c];}async function parallel() { const [a, b, c] = await Promise.all([ stepA(), stepB(), stepC() ]); return { a, b, c };}// 多个请求竞争,只用最快的结果async function race() { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 1000);
try { const result = await Promise.race([ fetch("/api/fast", { signal: controller.signal }), fetch("/api/reliable") ]); return result.json(); } finally { clearTimeout(timeoutId); }}const cache = new Map<string, Promise<string>>();
async function fetchWithCache(url: string): Promise<string> { if (cache.has(url)) { return cache.get(url)!; } const promise = fetch(url).then(r => r.text()); cache.set(url, promise); return promise;}async function parallelLimit( tasks: (() => Promise<void>)[], limit: number): Promise<void> { const executing: Promise<void>[] = [];
for (const task of tasks) { const p = task().finally(() => { executing.splice(executing.indexOf(p), 1); }); executing.push(p);
if (executing.length >= limit) { await Promise.race(executing); } }
await Promise.all(executing);}Python对比:
import asyncio
async def limited_parallel(tasks: list, limit: int): semaphore = asyncio.Semaphore(limit)
async def with_semaphore(task): async with semaphore: return await task()
await asyncio.gather(*[with_semaphore(t) for t in tasks])9.6 Promise vs Python asyncio
Section titled “9.6 Promise vs Python asyncio”核心概念对比
Section titled “核心概念对比”| 概念 | TypeScript Promise | Python asyncio |
|---|---|---|
| 异步单元 | Promise对象 | coroutine函数 |
| 等待 | await | await |
| 并发 | Promise.all | asyncio.gather |
| 错误传播 | try/catch | try/except |
| 生成器 | 无 | async def |
TypeScript Promise:
// 创建Promiseconst promise = new Promise((resolve, reject) => { setTimeout(() => resolve("done"), 1000);});
// 链式promise .then(result => result.toUpperCase()) .then(upper => console.log(upper)) .catch(err => console.error(err));
// async/awaitasync function main() { try { const result = await promise; console.log(result); } catch (e) { console.error(e); }}Python asyncio:
import asyncio
# 创建coroutineasync def async_operation(): await asyncio.sleep(1) return "done"
# 链式async def main(): try: result = await async_operation() print(result.upper()) except Exception as e: print(e)
asyncio.run(main())并发模式对比
Section titled “并发模式对比”TypeScript:
// 并行await Promise.all([taskA(), taskB(), taskC()]);
// 顺序for (const task of [taskA, taskB, taskC]) { await task();}Python:
# 并行await asyncio.gather(task_a(), task_b(), task_c())
# 顺序for task in [task_a, task_b, task_c]: await task()错误处理对比
Section titled “错误处理对比”TypeScript:
try { await riskyOperation();} catch (error) { if (error instanceof SpecificError) { handle(error); } throw error;}Python:
try: await risky_operation()except SpecificError as e: handle(e) raise资源清理对比
Section titled “资源清理对比”TypeScript:
const connection = await createConnection();try { const result = await connection.query(); return result;} finally { await connection.close();}Python:
connection = await create_connection()try: result = await connection.query() return resultfinally: await connection.close()
# 或者使用async withasync with create_connection() as connection: result = await connection.query()9.7 异步迭代器与生成器
Section titled “9.7 异步迭代器与生成器”AsyncIterator
Section titled “AsyncIterator”async function* generateNumbers(): AsyncGenerator<number> { for (let i = 0; i < 5; i++) { await new Promise(resolve => setTimeout(resolve, 100)); yield i; }}
async function main() { for await (const num of generateNumbers()) { console.log(num); }}AsyncIterable
Section titled “AsyncIterable”class AsyncQueue<T> implements AsyncIterable<T> { private queue: T[] = []; private resolvers: ((value: T) => void)[] = [];
async *[Symbol.asyncIterator](): AsyncIterableIterator<T> { while (true) { if (this.queue.length > 0) { const item = this.queue.shift()!; yield item; } else { const item = await new Promise<T>(resolve => { this.resolvers.push(resolve as any); }); yield item; } } }
push(item: T) { if (this.resolvers.length > 0) { const resolve = this.resolvers.shift()!; resolve(item); } else { this.queue.push(item); } }}9.8 本章小结
Section titled “9.8 本章小结”本章学习了TypeScript的异步编程:
-
Promise基础:
- 三个状态:pending、fulfilled、rejected
- then/catch/finally链式调用
- Promise.all/allSettled/race/any
-
async/await:
- async函数返回Promise
- await等待Promise完成
- 让异步代码更像同步
-
错误处理:
- try/catch/finally
- 错误传播
- 自定义错误类型
-
并发模式:
- 顺序执行
- 并行执行
- 限流和缓存
-
Python对比:
- Python用async def,TypeScript用async function
- Promise.all对应asyncio.gather
- 都支持async迭代器
练习9.1:Promise基础
Section titled “练习9.1:Promise基础”创建一个延迟解析的Promise,并在1秒后打印结果。
练习9.2:async/await
Section titled “练习9.2:async/await”将Promise链式调用改写成async/await形式。
练习9.3:Promise.all
Section titled “练习9.3:Promise.all”并行获取3个用户数据,并打印。
练习9.4:错误处理
Section titled “练习9.4:错误处理”实现一个带重试的异步函数。
练习9.5:Python对比
Section titled “练习9.5:Python对比”用Python asyncio实现同样的功能,对比语法差异。
下一章我们将学习TypeScript的类型声明与声明文件,了解如何为JavaScript代码提供类型信息,以及 DefinitelyTyped 的使用。