TypeScript异步编程简介
异步编程是一种代码编写方法,其中耗时操作(例如服务器请求、文件读取、定时器)不会阻塞程序主线程的执行。在现代Web开发中,异步不仅是一种便利,更是一种必要。JavaScript和TypeScript作为单线程语言,使用事件循环(Event Loop)来处理异步操作。
TypeScript为这一强大范式添加了静态类型检查,使代码更加可预测和安全。在本指南中,我们将深入探讨异步编程的各个方面:从经典的回调函数到完全类型化的现代async/await。
异步基础:从回调到Promise
回调函数的问题与"回调地狱"
最初,JavaScript中的异步是通过回调函数实现的。然而,这种方法很快导致代码难以阅读:
function loadData(callback: (data: string) => void) { setTimeout(() => { callback("数据已加载"); }, 1000);}
loadData((data) => { console.log(data); // 嵌套调用 loadData((data2) => { console.log(data2); });});这样的代码难以调试和维护。TypeScript虽然不能解决嵌套问题,但有助于对回调参数进行类型化。
Promise——摆脱回调地狱的救星
Promise是一个对象,可以处于三种状态之一:pending(等待中)、fulfilled(已成功完成)或rejected(因错误被拒绝)。TypeScript允许严格类型化Promise返回的数据类型:
function fetchUser(id: number): Promise<User> { return new Promise((resolve, reject) => { setTimeout(() => { if (id > 0) { resolve({ id, name: "伊万·彼得罗夫" }); } else { reject(new Error("无效ID")); } }, 500); });}
interface User { id: number; name: string;}
// 使用fetchUser(1).then(user => { console.log(user.name); // TypeScript知道user是User类型}).catch(error => { console.error(error.message);});得益于泛型Promise<User>,TypeScript编译器确保在.then()内部我们得到的是该确切类型的对象。
Async/Await:优雅的异步编程
语法与类型化
async和await关键字允许编写看起来像同步代码的异步代码。标记为async的函数始终返回一个Promise:
async function getGreeting(name: string): Promise<string> { return `你好,${name}!`;}
// 返回值类型为 Promise<string>const result: Promise<string> = getGreeting("世界");重要提示:如果async函数返回的不是Promise,TypeScript会自动将其包装成Promise。
实际逻辑示例
考虑一个典型场景——从API获取数据并进行处理:
interface Post { userId: number; id: number; title: string; body: string;}
async function fetchPosts(userId: number): Promise<Post[]> { const response = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`); if (!response.ok) { throw new Error(`HTTP错误: ${response.status}`); } const data: Post[] = await response.json(); return data;}
async function displayPosts() { try { const posts = await fetchPosts(1); console.log(`获取到 ${posts.length} 篇帖子:`); posts.forEach(post => console.log(`- ${post.title}`));