javascript怎样处理异步操作_promise如何使用【教程】

Promise构造函数必须传入执行器函数,它立即执行并接收resolve和reject参数;.then()可处理成功与失败,但推荐用.catch()统一捕获异常;async/await是Promise语法糖,需在async函数中使用;Promise.all全成功才resolve,Promise.race以最先settled者为准。

Promise 构造函数里必须传执行器函数

Promise 不是直接调用就能跑起来的,它需要一个「执行器函数」(executor),也就是 new Promise(fn) 中那个 fn。这个函数会立即执行,且接收两个参数:resolvereject —— 它们是 Promise 内部提供的回调,不是你随便定义的变量。

常见错误是漏写执行器、或把异步逻辑写在 new Promise 外面:

const p = new Promis

e(); // ❌ 报错:executor is required
const p = new Promise(() => {
  setTimeout(() => resolve('done'), 100); // ❌ resolve is not defined
});

正确写法:

const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 100);
});
  • resolve 触发 fulfilled 状态,值会传给后续 .then()
  • reject 触发 rejected 状态,等价于抛出异常,会被 .catch().then(null, fn) 捕获
  • 执行器中若抛出未捕获错误,Promise 自动进入 rejected 状态

.then() 的两个参数分别处理成功和失败

.then() 接收两个可选函数:第一个处理 fulfilled 值,第二个处理 rejected 原因。很多人只写第一个,结果错误被吞掉:

p.then(
  value => console.log(value),
  reason => console.error(reason) // ✅ 显式处理错误
);

但更推荐统一用 .catch(),因为:

  • .catch(fn) 等价于 .then(null, fn),语义更清晰
  • 它能捕获前面任意 .then() 中抛出的错误(链式调用中的异常冒泡)
  • 避免在每个 .then() 都重复写错误处理逻辑

注意:.catch() 只捕获 Promise rejection,不捕获同步 throw(除非 throw 发生在 Promise 执行器或 .then() 回调里)。

async/await 是 Promise 语法糖,不是替代品

async 函数返回的是 Promise 对象,await 后面的表达式必须是 Promise(或可转为 Promise 的值)。它只是让 Promise 链写起来像同步代码,底层没变。

常见误区:

  • await 不能用在普通函数里,必须包裹在 async 函数中
  • await 后面如果是普通值(如 await 42),会自动包装成 Promise.resolve(42)
  • 想并发执行多个 Promise,别写成 await p1; await p2;(串行),改用 await Promise.all([p1, p2])

错误示例:

function fetchUser() {
  return await fetch('/user'); // ❌ SyntaxError:await only valid in async function
}

正确写法:

async function fetchUser() {
  const res = await fetch('/user');
  return res.json();
}

Promise.all 和 Promise.race 的行为差异很关键

两者都接受 Promise 数组,但失败策略完全不同:

  • Promise.all([p1, p2, p3]):全部 fulfilled 才 resolve;只要一个 rejected,就立刻 reject(带第一个失败的 reason)
  • Promise.race([p1, p2, p3]):哪个 Promise 先 settle(fulfill 或 reject),就以它的结果为准

典型误用场景:用 Promise.race 做超时控制时,忘了它也会把先发生的 rejection 当作 race 结果。如果请求本身很快失败,超时逻辑就失效了。

安全的超时写法要确保 timeout Promise 只可能 fulfill,不能 reject:

const timeout = (ms, promise) =>
  Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('timeout')), ms)
    )
  ]);

真正容易被忽略的是:Promise 链一旦进入 rejected 状态,又没被 .catch() 拦住,就会变成 unhandled rejection —— 浏览器控制台报黄警告,Node.js 可能直接退出进程。别依赖全局 unhandledrejection 事件兜底,该 catch 的地方必须显式处理。