- 引用 7 篇资料作为参考
- 每一个前端都要学的 Promise 用法详细解析-CSDN博客
- 【JavaScript】前端一定要看的 Promise 用法详细解析_js promise使用-CSDN博客
- 《前端开发之promise》1. Promise 基本概念 Promise 是一个代表异步操作最终完成或失败的对象。它有 - 掘金
- BAT前端经典面试问题:史上最最最详细的手写Promise教程
- 理解JACRIPT PROMISE
- 关于 ES6 中Promise 的面试题_es6 promise面试题-CSDN博客
- 面试官必问!关于promise的10个高频面试题大家好,我是前端理想哥。 如果你正在准备前端开发的面试,那么今天这个话题 - 掘金
以下为前端 Promise 从基础到进阶的完整知识体系,包含核心概念、手写实现、高阶应用及高频面试题解析,结合最新规范与面试考点整理,助你系统掌握异步编程核心。
一、Promise 基础概念与核心机制 [citation:1][citation:2][citation:3]
1. 三大状态与生命周期
- Pending(待定):初始状态(如 new Promise() 执行时)。
- Fulfilled(已兑现):操作成功(resolve() 调用后),状态不可逆。
- Rejected(已拒绝):操作失败(reject() 调用后),状态不可逆。
面试聚焦:状态不可逆性是 Promise 可靠性的关键,错误回答“Resolved”会被扣分[citation:7]。
2. 基本用法
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve('成功数据') : reject('失败原因');
}, 1000);
});
promise
.then(res => console.log(res)) // 成功处理
.catch(err => console.error(err)) // 失败处理
.finally(() => console.log('清理')); // 必执行[citation:3]
3. 关键特性
- 微任务队列:then/catch/finally 回调进入微任务队列,优先于宏任务(如 setTimeout)执行。
- 值穿透:then() 接收非函数参数时,结果直接穿透到下一链式调用(如 .then(2) 忽略参数)[citation:6]。
二、链式调用与错误处理进阶 [citation:1][citation:3][citation:5]
1. 链式调用原理
- 返回普通值:直接作为下一 then 的输入。
- 返回新 Promise:下一 then 等待该 Promise 状态变更。
step1()
.then(result => step2(result)) // 返回Promise
.then(finalResult => console.log(finalResult));
2. 错误处理策略
- catch 捕获链中任意错误:替代 .then(null, errHandler) 更清晰。
- 穿透性:链中未处理的错误会一直传递直到被捕获。
fetchData()
.then(process)
.catch(err => { // 捕获fetchData或process中的错误
console.error(err);
return fallbackData; // 提供降级数据
});
三、静态方法深度解析 [citation:3][citation:6]
面试聚焦:
- all vs allSettled:all 关注全成功,allSettled 需处理全部结果[citation:7]。
- race 的竞态陷阱:若首个 Promise 失败,整个 race 直接拒绝,需谨慎处理错误。
四、手写 Promise 核心实现(面试高频) [citation:4]
1. 基础框架:状态管理与异步队列
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
};
// reject类似实现...
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
}
// 返回新Promise支持链式调用(需实现resolvePromise)...
}
}
2. 难点:链式调用与 resolvePromise
- 循环引用检测:若 then 返回自身,直接 reject(new TypeError(‘循环引用’))。
- 递归解析:处理返回值为 thenable 对象(如另一 Promise)的情况[citation:4]。
五、高频面试题与答案精析 [citation:6][citation:7]
1. 基础题:输出顺序分析
console.log(1);
new Promise(res => {
console.log(2);
res();
}).then(() => console.log(3));
console.log(4);
答案:1 → 2 → 4 → 3
解析:executor 同步执行,then 回调进入微任务队列[citation:6]。
2. 陷阱题:状态不可逆性
const p = new Promise((res, rej) => {
res('ok');
rej('error'); // 无效!
});
p.catch(err => console.log(err)); // 无输出
答案:仅输出 ok,因 res() 调用后状态已锁定[citation:2]。
3. 场景题:并发控制(3个并行上限)
async function limitConcurrency(urls, max = 3) {
const pool = new Set();
for (const url of urls) {
const task = loadImg(url);
pool.add(task);
task.then(() => pool.delete(task));
if (pool.size >= max) await Promise.race(pool);
}
await Promise.allSettled(pool); // 等待剩余任务
}
关键点:动态任务池 + Promise.race 触发新任务[citation:6]。
六、生产环境最佳实践 [citation:3][citation:5]
- 避免嵌套:用链式替代深层嵌套(回调地狱)。
- 全局错误处理:
window.addEventListener('unhandledrejection', e => {
e.preventDefault();
reportError(e.reason);
});
- 结合 async/await:
async function fetchUser() {
try {
const data = await fetch('/api');
return process(data);
} catch (err) {
// 统一错误分类处理
}
}
附:Promise 知识图谱
- 引用 9 篇资料作为参考
- 微信小程序 properties 多种类型
- Q promise nodejs序列_q.js promise_promise q.js - 腾讯云开发者社区 - 腾讯云
- 前端 ES6 之 Promise 实践应用与控制反转
- Promise 引入全新 API!效率提升 300%!
- resthighlevelclient soKeepAlive是什么意思
- 【前端】ES6 引入的异步编程解决方案Promise 详解
- promise详解-CSDN博客
- primise异步题目 - CSDN文库
- JavaScript Promise的错误处理(五)
Promise 在现代前端开发中的应用场景极为广泛,以下从实际开发角度分类整理其核心应用场景及具体实现方案,结合典型代码示例和面试常见问题分析:
🚀 一、异步请求封装(解决回调地狱)
- HTTP 请求封装
使用 Promise 封装 fetch 或 axios,统一处理成功/失败逻辑,避免多层嵌套:
function request(url, method = 'GET') {
return new Promise((resolve, reject) => {
fetch(url, { method })
.then(response => response.json())
.then(resolve)
.catch(reject);
});
}
// 使用
request('https://api.example.com/data')
.then(data => console.log(data))
.catch(error => console.error('请求失败:', error));
面试重点:
- 为什么需要封装?→ 统一错误处理、减少重复代码[citation:1][citation:6]
- 如何避免重复封装?→ 直接使用支持 Promise 的库(如 axios)[citation:3]
⚡ 二、并发控制与任务协调
- 并行请求(Promise.all)
同时发起多个独立请求,全部成功后再处理:
Promise.all([fetchUser(), fetchPosts(), fetchComments()])
.then(([user, posts, comments]) => renderPage(user, posts, comments))
.catch(error => showError('部分数据加载失败'));
场景:页面初始化需加载多个资源[citation:6][citation:7]
- 竞速场景(Promise.race)
设置请求超时机制:
const fetchWithTimeout = (url, timeout = 5000) =>
Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), timeout)
)
]);
场景:网络不稳定时避免长时间等待[citation:7][citation:8]
- 批量任务结果收集(Promise.allSettled)
无论成功失败,统一收集结果:
Promise.allSettled(tasks.map(task => task()))
.then(results =>
results.forEach(result =>
result.status === 'fulfilled'
? logSuccess(result.value)
: logError(result.reason)
)
);
场景:提交多个表单时需独立处理结果[citation:6][citation:7]
🔗 三、复杂流程链式调用
- 顺序依赖操作
下一步操作依赖上一步结果(如登录 → 获取用户信息 → 渲染):
login(user)
.then(token => getUserInfo(token))
.then(info => renderDashboard(info))
.catch(error => redirectToLogin());
优势:取代回调嵌套,逻辑线性化[citation:3][citation:6]
- 中间数据处理
链式调用中传递加工后的数据:
fetchData()
.then(raw => JSON.parse(raw))
.then(data => data.filter(item => item.active))
.then(activeItems => saveToCache(activeItems));
🛡️ 四、错误处理统一管理
- 全局异常捕获
通过 .catch 集中处理链中任意错误:
asyncOperation()
.then(step1)
.then(step2)
.catch(error => {
notify('操作失败', error);
throw error; // 继续向上抛出
});
最佳实践:链式调用末尾必加 .catch[citation:3][citation:9]
- 同步异常捕获(Promise.try)
ES2025 新特性,统一处理同步/异步错误:
Promise.try(() => {
if (!isValid(input)) throw new Error('非法输入');
return asyncCall(input);
}).catch(handleError);
优势:避免同步错误被遗漏[citation:4]
📂 五、文件与数据库操作
- 文件读取(Node.js)
封装 fs.readFile 为 Promise 风格:
const readFile = (path) =>
new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) =>
err ? reject(err) : resolve(data)
);
});
场景:配置文件读取、大数据处理[citation:7]
- 数据库查询
统一接口封装(如 MongoDB):
function queryDB(sql) {
return new Promise((resolve, reject) =>
db.query(sql, (err, results) =>
err ? reject(err) : resolve(results)
)
);
}
🔄 六、高级应用模式
- 异步任务队列
控制并发数(如最多同时处理 3 个任务):
async function runTasks(tasks, maxConcurrent = 3) {
const results = [];
for (const task of tasks) {
const current = task().then(res => results.push(res));
if (++count >= maxConcurrent) await Promise.race(running);
}
await Promise.all(running); // 等待剩余任务
return results;
}
场景:批量图片上传、API 限流[citation:7]
- 状态管理集成
在 Vue/React 中管理异步状态:
// Vue 示例
export default {
async created() {
this.loading = true;
try {
this.data = await fetchData();
} catch (e) {
this.error = e;
} finally {
this.loading = false;
}
}
};
💎 总结:Promise 核心价值与选型对比
⚠️ 避坑指南:
- 避免 new Promise 内直接 resolve 同步结果 → 导致时序混乱(用 Promise.resolve 替代)
- 禁止在循环中滥用 async/await → 用 Promise.all 优化性能
- 永远在链式调用末尾添加 .catch → 防止未处理拒绝(Unhandled Rejection)
通过结合 async/await 语法糖,Promise 能进一步简化代码结构,成为现代前端异步编程的核心范式。实际开发中应根据场景灵活选择并发控制策略,并始终贯彻错误优先原则[citation:6][citation:7]。