目录
- 一、 Promise的重要性
- 二、Promise基本概念
-
- 1.什么是Promise?
- 2.基本使用示例
- 三、 Promise核心特性深度解析
-
-
- Promise的状态不可逆
-
- Promise的微任务机制
-
- 四、 Promise API 深度解析
-
-
- Promise构造函数(简易实现)
-
- then 方法实现原理
-
- Promise解决过程(Promise Resolution Procedure)
-
- 五、 静态方法深度解析
-
-
- `Promise.resolve()`
-
- `Promise.reject()`
-
- `Promise.all()`
-
- `Promise.race()`
-
- `Promise.allSettled()`
-
- 六、 Promise链式调用深度解析
-
- 1.值穿透机制
- 2.错误冒泡机制
- 七、 高级应用场景
-
-
- Promise超时控制
-
- Promise重试机制
-
- Promise并发控制
-
- 八、 使用建议和常见误区
-
-
- 避免Promise嵌套(回调地狱)
-
- 总是返回 Promise
-
- 合理使用 async/await
-
- 九、 面试常见问题
-
-
- 输出顺序分析
-
- 错误处理与冒泡
-
- 十、 总结
一、 Promise的重要性
Promise 是现代 JavaScript 异步编程的基石,解决了传统的"回调地狱"问题。理解 Promise 对于掌握 async/await
、响应式编程等高级特性至关重要。
二、Promise基本概念
1.什么是Promise?
Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态:
- pending:初始状态,既不是成功,也不是失败
- fulfilled:操作成功完成
- rejected:操作失败
2.基本使用示例
javascript
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('操作成功!');
} else {
reject(new Error('操作失败!'));
}
}, 1000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error));
三、 Promise核心特性深度解析
1. Promise的状态不可逆
一旦状态改变(从 pending
→ fulfilled
或 rejected
),就无法再次更改。
javascript
const promise = new Promise((resolve, reject) => {
resolve('第一次resolve'); // 有效
resolve('第二次resolve'); // 被忽略
reject('错误'); // 被忽略
});
promise.then(result => console.log(result)); // 输出: 第一次resolve
2. Promise的微任务机制
Promise 的 .then()
和 .catch()
回调属于 微任务(microtask) ,在当前执行栈清空后立即执行,优先级高于宏任务(如 setTimeout
)。
javascript
console.log('脚本开始');
setTimeout(() => {
console.log('setTimeout - 宏任务');
}, 0);
Promise.resolve().then(() => {
console.log('Promise - 微任务');
});
console.log('脚本结束');
// 执行顺序:
// 脚本开始
// 脚本结束
// Promise - 微任务
// setTimeout - 宏任务
四、 Promise API 深度解析
1. Promise构造函数(简易实现)
javascript
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);
}
}
}
2. then 方法实现原理
javascript
then(onFulfilled, onRejected) {
// 参数处理:默认值和类型检查
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
const promise2 = new MyPromise((resolve, reject) => {
const handleFulfilled = () => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
const handleRejected = () => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
if (this.state === 'fulfilled') {
handleFulfilled();
} else if (this.state === 'rejected') {
handleRejected();
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
return promise2;
}
3. Promise解决过程(Promise Resolution Procedure)
这是 Promise/A+ 规范 的核心逻辑,用于处理 then
中返回值的解析。
javascript
function resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called = false; // 防止多次调用 resolve/reject
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
const then = x.then;
if (typeof then === 'function') {
// 认定为 thenable 对象(Promise 或类 Promise)
then.call(
x,
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject); // 递归解析
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x); // 普通对象
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x); // 基本类型值
}
}
五、 静态方法深度解析
1. Promise.resolve()
将任意值转换为 Promise 实例。
javascript
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
if (value && typeof value.then === 'function') {
return new MyPromise(value.then);
}
return new MyPromise(resolve => resolve(value));
}
// 使用示例
Promise.resolve(42).then(v => console.log(v)); // 42
2. Promise.reject()
返回一个被拒绝的 Promise。
javascript
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
3. Promise.all()
等待所有 Promise 成功,返回结果数组;任一失败则整体失败。
javascript
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let completedCount = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) resolve(results);
},
error => reject(error)
);
});
});
}
// 示例
Promise.all([p1, p2, p3]).then(values => console.log(values)); // [1, 2, 3]
4. Promise.race()
返回第一个完成(无论成功或失败)的 Promise 结果。
javascript
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
// 示例
Promise.race([p1, p2]).then(value => console.log(value)); // p2 先完成
5. Promise.allSettled()
等待所有 Promise 完成(无论成功或失败),返回包含状态的结果数组。
javascript
static allSettled(promises) {
return new MyPromise(resolve => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let completedCount = 0;
const processResult = (index, status, valueOrReason) => {
results[index] = status === 'fulfilled'
? { status, value: valueOrReason }
: { status, reason: valueOrReason };
completedCount++;
if (completedCount === promises.length) resolve(results);
};
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => processResult(index, 'fulfilled', value),
reason => processResult(index, 'rejected', reason)
);
});
});
}
// 示例
Promise.allSettled([p1, p2]).then(results => console.log(results));
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: '错误' }
// ]
六、 Promise链式调用深度解析
1.值穿透机制
javascript
Promise.resolve(1)
.then(2) // 非函数,被忽略
.then()
.then(value => console.log(value)); // 1
// 相当于:
Promise.resolve(1)
.then(v => v)
.then(v => v)
.then(v => console.log(v));
2.错误冒泡机制
javascript
Promise.resolve()
.then(() => {
throw new Error('第一个错误');
})
.then(() => console.log('不会执行'))
.catch(error => {
console.error('捕获到错误:', error.message); // 第一个错误
})
.then(() => {
console.log('catch之后继续执行');
return '新的值';
})
.then(value => console.log('接收到:', value)); // 接收到: 新的值
七、 高级应用场景
1. Promise超时控制
javascript
function timeoutPromise(promise, timeout) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`Operation timed out after ${timeout}ms`));
}, timeout);
});
return Promise.race([promise, timeoutPromise]);
}
// 使用示例
timeoutPromise(fetch('/api/data'), 5000)
.then(res => res.json())
.catch(err => console.error(err));
2. Promise重试机制
javascript
function retryPromise(fn, retries = 3, delay = 1000) {
return new Promise((resolve, reject) => {
const attempt = (attemptCount) => {
fn()
.then(resolve)
.catch(error => {
if (attemptCount >= retries) {
reject(error);
} else {
console.log(`第${attemptCount}次尝试失败,${delay}ms后重试...`);
setTimeout(() => attempt(attemptCount + 1), delay);
}
});
};
attempt(1);
});
}
// 使用示例
retryPromise(() => fetch('/api/data'), 3, 1000);
3. Promise并发控制
javascript
class PromisePool {
constructor(concurrency = 5) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
add(task) {
return new Promise((resolve, reject) => {
this.queue.push({ task, resolve, reject });
this.run();
});
}
run() {
while (this.running < this.concurrency && this.queue.length) {
const { task, resolve, reject } = this.queue.shift();
this.running++;
task()
.then(resolve, reject)
.finally(() => {
this.running--;
this.run();
});
}
}
}
// 使用示例
const pool = new PromisePool(3);
const tasks = Array(10).fill(0).map((_, i) => () =>
new Promise(resolve =>
setTimeout(() => {
console.log(`任务 ${i} 完成`);
resolve(i);
}, Math.random() * 2000)
)
);
tasks.forEach(task => pool.add(task));
八、 使用建议和常见误区
1. 避免Promise嵌套(回调地狱)
❌ 错误写法:
javascript
getUser(userId)
.then(user => {
getPosts(user.id)
.then(posts => {
getComments(posts[0].id)
.then(comments => console.log(comments));
});
});
✅ 正确写法(链式调用):
javascript
getUser(userId)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error(error));
2. 总是返回 Promise
❌ 忘记 return
:
javascript
getUser(userId)
.then(user => {
getPosts(user.id); // ❌ 忘记 return
})
.then(posts => console.log(posts)); // undefined
✅ 正确做法:
javascript
getUser(userId)
.then(user => {
return getPosts(user.id); // ✅
})
.then(posts => console.log(posts)); // 正确数据
3. 合理使用 async/await
javascript
async function fetchUserData(userId) {
try {
const user = await getUser(userId);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
return { user, posts, comments };
} catch (error) {
console.error('获取失败:', error);
throw error;
}
}
// 并行优化
async function fetchUserDataParallel(userId) {
try {
const [user, posts] = await Promise.all([
getUser(userId),
getPosts(userId)
]);
const comments = await getComments(posts[0].id);
return { user, posts, comments };
} catch (error) {
console.error('获取失败:', error);
throw error;
}
}
九、 面试常见问题
1. 输出顺序分析
javascript
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve()
.then(() => console.log('3'))
.then(() => console.log('4'));
console.log('5');
// 输出顺序: 1 → 5 → 3 → 4 → 2
解析:同步代码先执行(1, 5),微任务(Promise)在宏任务(setTimeout)前执行。
2. 错误处理与冒泡
javascript
Promise.resolve()
.then(() => {
throw new Error('then错误');
})
.catch(error => {
console.log('捕获错误:', error.message);
throw new Error('catch中的新错误');
})
.then(() => console.log('不会执行'))
.catch(error => {
console.log('最终捕获:', error.message);
});
// 输出:
// 捕获错误: then错误
// 最终捕获: catch中的新错误
十、 总结
掌握 Promise 的深度原理和高级用法,能够让你在复杂的异步编程场景中游刃有余,为学习更高级的异步模式(如 async/await
、RxJS 等)打下坚实基础。
核心要点回顾:
- Promise 状态不可逆
.then()
是微任务resolvePromise
是链式调用的核心- 静态方法
all
、race
、allSettled
的使用场景 - 避免嵌套、合理使用
return
和async/await
深入理解 Promise,是迈向专业前端开发的关键一步!