glownight

返回

一、Promise 是什么?#

Promise 是 JavaScript 中处理异步操作的对象,代表一个尚未完成但预期将来会完成的操作 。它是回调函数的升级版,解决了”回调地狱”问题。

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    resolve('成功!');  // 将 Promise 状态变为 fulfilled
  }, 1000);
});
javascript

二、为什么需要 Promise?#

回调地狱(Callback Hell)#

// ❌ 嵌套回调,代码横向发展,难以维护
getData(function(a) {
  getMoreData(a, function(b) {
    getMoreData(b, function(c) {
      getMoreData(c, function(d) {
        console.log(d);
      });
    });
  });
});
javascript

Promise 链式调用#

// ✅ 链式调用,代码纵向发展,清晰可读
getData()
  .then(a => getMoreData(a))
  .then(b => getMoreData(b))
  .then(c => getMoreData(c))
  .then(d => console.log(d))
  .catch(err => console.error(err));
javascript

三、Promise 的三种状态#

Promise 对象有三种状态,状态一旦改变就不可再次改变

         ┌─────────────┐
         │   pending   │  ← 初始状态:进行中
         │  (待定)    │
         └──────┬──────┘

      ┌─────────┴─────────┐
      │                   │
      ▼                   ▼
┌─────────────┐    ┌─────────────┐
│  fulfilled  │    │  rejected   │
│  (已成功)  │    │  (已失败)  │
│             │    │             │
│ resolve()   │    │  reject()   │
│ 触发         │    │  触发        │
└─────────────┘    └─────────────┘
plaintext

四、创建 Promise#

基础语法#

const promise = new Promise((resolve, reject) => {
  // resolve: 异步操作成功时调用
  // reject:  异步操作失败时调用
  
  const success = true;
  
  if (success) {
    resolve('操作成功');  // 状态变为 fulfilled,传递结果
  } else {
    reject('操作失败');   // 状态变为 rejected,传递错误原因
  }
});
javascript

实际示例:封装异步请求#

function fetchUser(userId) {
  return new Promise((resolve, reject) => {
    fetch(`https://api.example.com/users/${userId}`)
      .then(response => {
        if (!response.ok) {
          reject(new Error('网络请求失败'));
        }
        return response.json();
      })
      .then(data => resolve(data))
      .catch(error => reject(error));
  });
}
javascript

五、消费 Promise:then / catch / finally#

.then() —— 处理成功#

promise
  .then(value => {
    console.log(value);  // '操作成功'
    return value + '!!!'; // 返回值传递给下一个 then
  })
  .then(value => {
    console.log(value);  // '操作成功!!!'
  });
javascript

then 的两种回调

promise.then(
  onFulfilled,  // 成功时执行(可选)
  onRejected    // 失败时执行(可选,但推荐用 catch)
);
javascript

.catch() —— 处理失败#

promise
  .then(value => {
    throw new Error('出错了');
  })
  .catch(error => {
    console.error(error.message);  // '出错了'
  });
javascript

.finally() —— 无论成败都执行#

promise
  .then(value => console.log(value))
  .catch(error => console.error(error))
  .finally(() => {
    console.log('无论成功失败,都会执行');
    // 常用于关闭加载动画、释放资源
  });
javascript

六、Promise 的静态方法#

Promise.resolve() —— 快速创建成功 Promise#

Promise.resolve('立即成功').then(value => console.log(value));

// 等价于:
new Promise(resolve => resolve('立即成功'));
javascript

Promise.reject() —— 快速创建失败 Promise#

Promise.reject('立即失败').catch(reason => console.error(reason));
javascript

Promise.all() —— 全部成功才算成功#

const p1 = fetch('/api/user');
const p2 = fetch('/api/posts');
const p3 = fetch('/api/comments');

Promise.all([p1, p2, p3])
  .then(([user, posts, comments]) => {
    // 三个请求都成功,结果按顺序返回
    console.log(user, posts, comments);
  })
  .catch(error => {
    // 任意一个失败,立即进入 catch
    console.error('至少一个请求失败:', error);
  });
javascript

特点:并行执行,全部成功返回结果数组;一个失败立即失败。

Promise.race() —— 谁先完成用谁#

const fetchData = fetch('/api/data');
const timeout = new Promise((_, reject) => 
  setTimeout(() => reject(new Error('超时')), 5000)
);

Promise.race([fetchData, timeout])
  .then(data => console.log(data))
  .catch(err => console.error(err));  // 如果 5 秒内没拿到数据,显示超时
javascript

特点:返回最快完成的那个 Promise 的结果。

Promise.allSettled() —— 等待全部完成(无论成败)#

const promises = [
  Promise.resolve('成功1'),
  Promise.reject('失败'),
  Promise.resolve('成功2')
];

Promise.allSettled(promises).then(results => {
  console.log(results);
  // [
  //   { status: 'fulfilled', value: '成功1' },
  //   { status: 'rejected', reason: '失败' },
  //   { status: 'fulfilled', value: '成功2' }
  // ]
});
javascript

特点:等待所有 Promise 完成,返回每个 Promise 的状态和结果/原因。不会短路

Promise.any() —— 任意一个成功#

Promise.any([
  Promise.reject('失败1'),
  Promise.resolve('成功!'),
  Promise.resolve('也成功')
])
.then(value => console.log(value))  // '成功!'(第一个成功的)
.catch(error => console.error(error));  // 如果全部失败,进入 AggregateError
javascript

特点:返回第一个成功的 Promise;如果全部失败,抛出 AggregateError


七、async / await —— Promise 的语法糖#

async/await 让异步代码看起来像同步代码,本质上还是 Promise 。

基本用法#

async function getUser() {
  try {
    const response = await fetch('/api/user');  // 等待 Promise 完成
    const user = await response.json();          // 等待下一个 Promise
    console.log(user);
    return user;  // 自动包装为 Promise.resolve(user)
  } catch (error) {
    console.error('获取用户失败:', error);
    throw error;  // 自动包装为 Promise.reject(error)
  }
}

// 调用
getUser().then(user => console.log(user));
javascript

async 函数总是返回 Promise#

async function foo() {
  return 'hello';  // 等价于 Promise.resolve('hello')
}

async function bar() {
  throw new Error('oops');  // 等价于 Promise.reject(new Error('oops'))
}
javascript

await 的注意事项#

// ✅ 并行执行(推荐)
const [user, posts] = await Promise.all([
  fetchUser(),
  fetchPosts()
]);

// ❌ 串行执行(慢)
const user = await fetchUser();    // 等 1 秒
const posts = await fetchPosts();  // 再等 1 秒,总共 2 秒
javascript

八、手写 Promise(面试常考)#

理解 Promise 的最佳方式是手写一个简化版:

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        });
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        });
      } else {
        // pending 状态,存入回调队列
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }
}

// 使用
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => resolve('成功'), 1000);
});

p.then(value => console.log(value));  // 1 秒后输出 "成功"
javascript

九、常见面试题#

题目 1:输出顺序#

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');
javascript

答案1 → 4 → 3 → 2

解析:同步代码(1、4)先执行;Promise.then 是微任务,优先于 setTimeout 宏任务。


题目 2:Promise 链#

Promise.resolve(1)
  .then(x => x + 1)        // 返回 2
  .then(x => { throw new Error('oops') })
  .catch(() => 3)           // 捕获错误,返回 3
  .then(x => x + 1)        // 返回 4
  .then(console.log);       // 输出 4
javascript

答案4


题目 3:async/await 与 Promise#

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
async1();
new Promise(resolve => {
  console.log('promise1');
  resolve();
}).then(() => console.log('promise2'));
console.log('script end');
javascript

答案script start → async1 start → async2 → promise1 → script end → async1 end → promise2 → setTimeout


十、最佳实践#

场景推荐做法
处理异步错误始终使用 .catch()try/catch
多个独立请求使用 Promise.all() 并行
超时控制使用 Promise.race()
需要等待全部结果使用 Promise.allSettled()
链式调用每个 .then() 返回新 Promise
现代项目优先使用 async/await
循环中发请求for...of + await 代替 forEach
// ❌ forEach 不会等待
urls.forEach(async url => {
  await fetch(url);  // 并发执行,不等待
});

// ✅ for...of 会顺序等待
for (const url of urls) {
  await fetch(url);  // 顺序执行,等待每个完成
}
javascript

Promise 是 JavaScript 异步编程的基石,掌握它之后,再配合事件循环的理解,就能彻底搞懂 JS 的异步机制。

Promise
作者 glownight
发布于 2026年4月27日