Promise终极指南:从回调地狱到异步天堂
本文最后更新于 47 天前,其中的信息可能已经有所发展或是发生改变。

一、为什么我们需要Promise?

1.1 回调地狱的噩梦

// 传统回调金字塔
getUser(id, function(user) {
  getPosts(user.id, function(posts) {
    getComments(posts.id, function(comments) {
      renderUI(user, posts, comments);
    }, errorHandler);
  }, errorHandler);
}, errorHandler);

1.2 Promise的救赎

// Promise链式调用
getUser(id)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts.id))
  .then(comments => renderUI(comments))
  .catch(errorHandler);

1.3 核心优势对比

特性 回调函数 Promise
可读性 ❌ 嵌套地狱 ✅ 链式调用
错误处理 ❌ 分散处理 ✅ 集中捕获
异步流程控制 ❌ 手动实现 ✅ 内置方法
状态管理 ❌ 不可控 ✅ 明确状态

二、Promise核心机制深度解析

2.1 三大状态生命周期

stateDiagram-v2
  [*] --> pending
  pending --> fulfilled: resolve()
  pending --> rejected: reject()
  fulfilled --> [*]
  rejected --> [*]

2.2 创建Promise的三种姿势

// 1. 基础创建
const timerPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Done!'), 1000);
});

// 2. 快捷方法
const success = Promise.resolve('Immediate');
const failure = Promise.reject(new Error('Oops!'));

// 3. 包装回调函数
const promisify = fn => (...args) => 
  new Promise((resolve, reject) => {
    fn(...args, (err, data) => {
      err ? reject(err) : resolve(data);
    });
  });

三、高级用法实战手册

3.1 并发控制四剑客

// 1. 全部成功
Promise.all([fetchA(), fetchB()])
  .then(([a, b]) => {/* 处理数据 */});

// 2. 竞速模式
Promise.race([timeout(500), fetchData()]);

// 3. 全量结算
Promise.allSettled([req1, req2])
  .then(results => results.filter(r => r.status === 'fulfilled'));

// 4. 首个成功
Promise.any([fallbackAPI1(), fallbackAPI2()]);

3.2 错误处理进阶

// 1. 穿透捕获
fetchData()
  .then(data => process(data))
  .catch(err => {
    console.error('请求失败:', err);
    return getCacheData(); // 降级方案
  });

// 2. 局部捕获
fetchData()
  .then(data => {
    return process(data).catch(e => {/* 处理步骤错误 */});
  });

// 3. 全局监听
window.addEventListener('unhandledrejection', event => {
  reportError(event.reason);
});

四、async/await革命性改进

4.1 同步写法异步逻辑

async function loadDashboard() {
  try {
    const user = await getUser();
    const [posts, notifications] = await Promise.all([
      getPosts(user.id),
      getNotifications(user.id)
    ]);
    return { user, posts, notifications };
  } catch (error) {
    await logError(error);
    throw new Error('加载失败');
  } finally {
    hideLoading();
  }
}

4.2 性能优化技巧

// 错误示范:顺序await
async function slowFetch() {
  const a = await fetchA(); // 等待1秒
  const b = await fetchB(); // 再等待1秒
  return a + b; // 总耗时2秒
}

// 正确做法:并行执行
async function fastFetch() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return a + b; // 总耗时1秒
}

五、十大高频问题解决方案

5.1 如何取消Promise?

function cancellablePromise(fn) {
  let cancel;
  const promise = new Promise((resolve, reject) => {
    cancel = reject;
    fn(resolve, reject);
  });
  return { promise, cancel };
}

// 使用示例
const { promise, cancel } = cancellablePromise(resolve => {
  setTimeout(() => resolve('Data'), 2000);
});
cancelButton.addEventListener('click', () => cancel('用户取消'));

5.2 超时控制

function timeoutPromise(ms, promise) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error(`超时 ${ms}ms`)), ms)
    )
  ]);
}

六、Promise最佳实践

  1. 避免嵌套陷阱
// ❌ 错误嵌套
promise.then(result => {
  anotherPromise(result).then(/* ... */);
});

// ✅ 链式优化
promise
  .then(result => anotherPromise(result))
  .then(/* ... */);
  1. 异常穿透原则
fetchData()
  .then(data => {
    if (!data.valid) throw new Error('无效数据');
    return process(data);
  })
  .catch(handleError); // 捕获所有异常
  1. 合理使用微任务
// 微任务执行顺序
Promise.resolve().then(() => console.log('微任务1'));
setTimeout(() => console.log('宏任务'), 0);
Promise.resolve().then(() => console.log('微任务2'));

// 输出顺序:
// 微任务1 → 微任务2 → 宏任务

🚀 升级你的异步代码

重构前(回调) 重构后(Promise)
fs.readFile('a.txt', (err, data) => { ... }) fs.promises.readFile('a.txt').then(...)
setTimeout(() => callback(), 1000) new Promise(r => setTimeout(r, 1000)).then(...)
XMLHttpRequest fetch().then(res => res.json())

根据Chrome DevTools统计,合理使用Promise可以使异步代码执行效率提升40%


// 终极示例:实现Promise队列
class PromiseQueue {
  constructor(concurrency = 1) {
    this.queue = [];
    this.running = 0;
    this.concurrency = concurrency;
  }

  add(task) {
    this.queue.push(task);
    this.next();
  }

  next() {
    while (this.running < this.concurrency && this.queue.length) {
      const task = this.queue.shift();
      task().finally(() => {
        this.running--;
        this.next();
      });
      this.running++;
    }
  }
}

// 使用示例
const queue = new PromiseQueue(2);
[1,2,3,4,5].forEach(i => 
  queue.add(() => 
    fetch(`/api/item/${i}`).then(/*...*/)
  )
);
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇