TypeScript — Promise

Promise

This article is extracted from the chat log with AI. Please identify it with caution.

1. 什么是 Promise? #

在 JavaScript / TypeScript 中,Promise 表示一个异步操作的最终结果(成功或失败)。
它有三种状态:

  • pending(进行中)

  • fulfilled(成功)

  • rejected(失败)

一旦状态从 pending 变成 fulfilledrejected,就不可再改变。


2. Promise 的语法 #

const p = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    resolve("ok");   // 成功
    // reject(new Error("fail")); // 失败
  }, 1000);
});

p.then(result => console.log("成功:", result))
 .catch(err => console.error("失败:", err))
 .finally(() => console.log("完成"));

解释:

  • resolve(value) → 将 Promise 状态设为 fulfilled

  • reject(error) → 将 Promise 状态设为 rejected

  • .then() → 成功时回调

  • .catch() → 失败时回调

  • .finally() → 无论成功失败都会执行


3. Promise 的链式调用 #

function task1(): Promise<number> {
  return Promise.resolve(1);
}

function task2(n: number): Promise<number> {
  return Promise.resolve(n + 1);
}

task1()
  .then(res => task2(res))
  .then(final => console.log("结果:", final)); // 输出 2

这里通过链式调用保证 前一个结果传给下一个异步任务


4. Promise 并发执行 #

如果多个异步任务可以并行,推荐用 Promise.all

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);

Promise.all([p1, p2]).then(([a, b]) => {
  console.log(a + b); // 3
});

还有:

  • Promise.race([p1, p2]) → 谁先完成就返回谁

  • Promise.allSettled([p1, p2]) → 等待所有 Promise 都有结果(不管成功失败)


二、async/await vs Promise.then 对比 #

特性Promise.then 写法async/await 写法
可读性链式回调,容易嵌套多层看起来像同步代码,线性结构
错误处理需要 .catch() 或链式处理try...catch,和同步异常一样
调试体验栈信息可能被截断更接近同步栈,调试更清晰
并发执行Promise.all([...])同样用 Promise.all([...]),但结合 await 更直观
返回值直接得到 Promiseasync 函数自动返回 Promise
语法复杂度初学者不直观更贴近同步思维

示例对比 #

Promise.then 写法 #

function fetchData(): Promise<string> {
  return new Promise(resolve => setTimeout(() => resolve("data"), 1000));
}

fetchData()
  .then(res => {
    console.log("Got:", res);
    return res + " processed";
  })
  .then(final => console.log("Final:", final))
  .catch(err => console.error("Error:", err));

async/await 写法 #

async function main() {
  try {
    const res = await fetchData();
    console.log("Got:", res);

    const final = res + " processed";
    console.log("Final:", final);
  } catch (err) {
    console.error("Error:", err);
  }
}

main();

是不是 async/await 写法更像同步流程?

Promise 的使用场景 #

一、顺序执行(串行) #

有时候异步任务需要 一个接一个执行,前一个结果传递给下一个:

Promise.then #
function task1(): Promise<number> {
  return Promise.resolve(1);
}

function task2(n: number): Promise<number> {
  return Promise.resolve(n + 1);
}

task1()
  .then(res => task2(res))
  .then(result => console.log("串行结果:", result)); // 输出 2
async/await #
async function run() {
  const res1 = await task1();
  const res2 = await task2(res1);
  console.log("串行结果:", res2);
}
run();

二、并行执行 #

多个任务可以同时进行,等待所有完成:

const t1 = Promise.resolve("A");
const t2 = Promise.resolve("B");

Promise.all([t1, t2]).then(([a, b]) => {
  console.log("并行结果:", a, b); // "A B"
});

⚡ 适合:同时请求多个接口。
⚠ 注意:只要有一个失败,整个 Promise.all 就会 reject。


三、竞速执行(取最快的) #

如果只关心第一个完成的结果,用 Promise.race

function delay(ms: number, value: string) {
  return new Promise(resolve => setTimeout(() => resolve(value), ms));
}

Promise.race([delay(1000, "A"), delay(500, "B")])
  .then(result => console.log("最快的结果:", result)); // "B"

⚡ 适合:多个数据源取最快响应。


四、所有结果(无论成功失败) #

有时候我们需要 收集所有任务结果,不管它们成功还是失败,用 Promise.allSettled

const tasks = [
  Promise.resolve("ok"),
  Promise.reject("error")
];

Promise.allSettled(tasks).then(results => {
  results.forEach(r => console.log(r.status, r.value ?? r.reason));
});
// 输出:fulfilled ok
//      rejected error

⚡ 适合:批量任务统计。


五、错误处理与重试 #

普通错误处理 #

fetch("https://api.example.com")
  .then(res => res.json())
  .catch(err => console.error("请求失败:", err));

重试机制(常见模式) #

function retry<T>(fn: () => Promise<T>, times: number): Promise<T> {
  return fn().catch(err => {
    if (times <= 0) throw err;
    return retry(fn, times - 1);
  });
}

retry(() => fetch("https://api.example.com"), 3)
  .then(res => console.log("成功"))
  .catch(err => console.error("失败:", err));

⚡ 适合:网络请求可能临时失败的情况。


六、超时控制 #

Promise 自带没有超时机制,可以自己封装:

function withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
  return Promise.race([
    p,
    new Promise<never>((_, reject) =>
      setTimeout(() => reject(new Error("超时")), ms)
    )
  ]);
}

withTimeout(fetch("https://api.example.com"), 2000)
  .then(res => console.log("完成"))
  .catch(err => console.error("失败:", err.message));

⚡ 适合:请求卡住时强制结束。


七、控制并发数 #

比如要下载 100 个文件,但不能同时开 100 个请求。可以用队列控制:

async function limitConcurrency<T>(
  tasks: (() => Promise<T>)[],
  limit: number
): Promise<T[]> {
  const results: T[] = [];
  const executing: Promise<void>[] = [];

  for (const task of tasks) {
    const p = task().then(r => results.push(r));
    executing.push(p);

    if (executing.length >= limit) {
      await Promise.race(executing);
      executing.splice(executing.findIndex(e => e === p), 1);
    }
  }

  await Promise.all(executing);
  return results;
}

⚡ 适合:批量下载 / 批量爬取数据。


八、总结 #

  • 顺序执行.then 链 / await

  • 并行执行Promise.all

  • 竞速执行Promise.race

  • 所有结果Promise.allSettled

  • 错误重试 → 封装 retry

  • 超时控制Promise.race + setTimeout

  • 控制并发 → 手写队列 / 使用第三方库(如 p-limit)

本文共 1699 字,创建于 Aug 26, 2025

相关标签: Frontend, ByAI, ChatGPT, TypeScript