5. 你是怎么理解ES6中 Promise的?使用场景?
你是否理解Promise 解决了什么问题你能不能说清楚三种状态和不可逆性你是否熟悉常用方法和静态方法你能不能结合实际场景来说使用价值你有没有意识到async/await 和 Promise 的关系。
一、先给面试官一个结论版
如果面试官问 "你怎么理解 Promise?" ,不要上来就背 API。
更好的开场是先说本质:
Promise 是 ES6 引入的一种用于处理异步操作的解决方案。
它的核心价值是:把异步操作的最终结果(成功或失败)用一种统一的方式表达出来,避免了传统回调函数嵌套带来的"回调地狱"问题,让异步代码可以写得像同步一样清晰。
这段开场就很有力度。
二、为什么需要 Promise?
要理解 Promise,先要理解它解决了什么问题。
回调地狱
ES6 之前,异步操作主要依赖回调函数:
ajax('/api/user', function(user) {
ajax('/api/orders?id=' + user.id, function(orders) {
ajax('/api/detail?id=' + orders[0].id, function(detail) {
// 终于拿到数据...
})
})
})
这种写法有几个问题:
- 嵌套层次深,可读性差
- 错误处理复杂,每一层都要单独处理
- 逻辑难以维护和复用
Promise 就是为了解决这些问题而生的。
三、Promise 是什么?
1)本质
Promise 是一个对象,代表一个 异步操作的最终完成或失败。
它有三种状态:
| 状态 | 说明 |
|---|---|
pending |
进行中,初始状态 |
fulfilled |
已成功,操作完成 |
rejected |
已失败,操作出错 |
状态特点
- 状态只能由
pending变成fulfilled,或pending变成rejected - 一旦状态确定,就不会再改变
这个不变性非常重要,面试一定要说。
2)基本用法
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true
if (success) {
resolve('操作成功')
} else {
reject('操作失败')
}
}, 1000)
})
promise
.then(result => {
console.log(result) // 操作成功
})
.catch(err => {
console.log(err) // 操作失败
})
3)关键方法
.then()
接收成功的结果,返回一个新的 Promise。
promise.then(value => {
console.log(value)
})
.catch()
接收失败的结果,相当于 .then(null, onRejected)。
promise.catch(err => {
console.log(err)
})
.finally()
无论成功还是失败都会执行(ES2018,但常和 Promise 一起考)。
promise.finally(() => {
console.log('结束了')
})
四、Promise 的链式调用
这是 Promise 解决"回调地狱"的核心机制。
每次 .then() 都会返回一个新的 Promise,所以可以链式调用:
ajax('/api/user')
.then(user => ajax('/api/orders?id=' + user.id))
.then(orders => ajax('/api/detail?id=' + orders[0].id))
.then(detail => {
console.log(detail)
})
.catch(err => {
console.log(err)
})
和回调地狱相比,代码更扁平、更清晰。
面试加分说法
链式调用的核心是
.then()每次都返回一个新的 Promise,而不是原来的那个。
这就让异步操作可以像同步一样"排队"执行。
五、Promise 的静态方法
这部分非常高频,面试必问。
1)Promise.all()
作用
等待所有 Promise 都成功,才算成功;只要一个失败,就失败。
Promise.all([
fetch('/api/a'),
fetch('/api/b'),
fetch('/api/c')
]).then(([a, b, c]) => {
console.log(a, b, c)
}).catch(err => {
console.log(err)
})
适用场景
- 多个请求同时发出,等全部完成再处理
- 并行请求,且结果全部需要
面试加分点
Promise.all()是并行执行,不是串行。结果数组的顺序和传入的 Promise 顺序一致,和谁先完成无关。
2)Promise.race()
作用
多个 Promise 中,谁最先改变状态就以谁为准。
Promise.race([
fetch('/api/a'),
new Promise((_, reject) => setTimeout(reject, 3000, '超时'))
]).then(result => {
console.log(result)
}).catch(err => {
console.log(err) // 超时
})
适用场景
- 超时控制
- 竞速场景
3)Promise.allSettled()
作用
等所有 Promise 都完成(不管成功还是失败),返回每个 Promise 的结果。
Promise.allSettled([
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
]).then(results => {
results.forEach(result => {
console.log(result)
})
})
// { status: 'fulfilled', value: 1 }
// { status: 'rejected', reason: 'error' }
// { status: 'fulfilled', value: 3 }
与 Promise.all() 的区别
Promise.all():有一个失败就结束Promise.allSettled():等全部结束,不管成不成功
适用场景
- 批量请求,希望知道每一个的结果,不管成败
- 上报场景,不能因为某个接口失败就漏掉其他的
4)Promise.any()
作用
只要有一个 Promise 成功,就成功;所有都失败,才失败。
Promise.any([
Promise.reject('err1'),
Promise.resolve('ok'),
Promise.reject('err2')
]).then(result => {
console.log(result) // ok
})
和 Promise.race() 的区别
Promise.race():最快的那个,不管成功还是失败Promise.any():最快成功的那个
5)Promise.resolve() / Promise.reject()
快速创建一个已经成功或失败的 Promise:
Promise.resolve(1).then(v => console.log(v)) // 1
Promise.reject('err').catch(e => console.log(e)) // err
六、Promise 的使用场景
这部分是面试里很想听到的,要结合实际说。
1)接口请求封装
function request(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(res => res.json())
.then(data => resolve(data))
.catch(err => reject(err))
})
}
2)多个请求并行
Promise.all([
request('/api/user'),
request('/api/config')
]).then(([user, config]) => {
// 全部拿到再处理
})
3)超时控制
function timeout(promise, ms) {
const timer = new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), ms)
)
return Promise.race([promise, timer])
}
4)串行执行异步任务
const tasks = [taskA, taskB, taskC]
tasks.reduce((prev, task) => {
return prev.then(() => task())
}, Promise.resolve())
5)Loading 状态管理
setLoading(true)
request('/api/data')
.then(data => {
renderData(data)
})
.catch(err => {
showError(err)
})
.finally(() => {
setLoading(false)
})
6)懒加载 / 图片预加载
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = src
})
}
七、Promise 的缺点
主动说出缺点,会让面试官觉得你很成熟。
1)无法取消
Promise 一旦创建就会执行,无法中途取消。
这是它比较明显的局限。
2)内部错误不会抛出到外层
如果没有 .catch(),内部的错误可能被静默吞掉:
const p = new Promise(() => {
throw new Error('出错了')
})
// 没有 .catch(),这个错误不会抛到外部
3)无法监测当前进度
Promise 只有三种状态,无法知道当前处于"第几步"。
八、Promise 和 async/await 的关系
这是面试里最常被追问的内容,要准备好。
async/await是 Promise 的语法糖,它并没有取代 Promise,而是让 Promise 的使用方式更直观。async函数的返回值是一个 Promise,await的本质是在.then()上的等待。
// Promise 写法
request('/api/data')
.then(data => console.log(data))
.catch(err => console.log(err))
// async/await 写法
async function getData() {
try {
const data = await request('/api/data')
console.log(data)
} catch (err) {
console.log(err)
}
}
面试加分说法
我通常优先用
async/await,因为它更贴近同步写法,可读性更好。
但在需要并行执行的场景,还是会配合Promise.all()使用,不能全部改成串行await,否则会损失并发性能。
这句非常加分。
九、面试标准回答
我理解 Promise 是 ES6 引入的用于处理异步操作的解决方案。
它的本质是一个对象,代表一个异步操作的最终结果,有三种状态:pending、fulfilled、rejected,而且状态一旦确定就不可逆。它的核心价值在于解决了回调地狱的问题。传统回调嵌套深、错误处理难,而 Promise 通过链式调用,让异步代码可以写得更扁平、更清晰。
从方法上看,常用的有
.then()、.catch()、.finally(),以及静态方法Promise.all()、Promise.race()、Promise.allSettled()、Promise.any()。
其中Promise.all()适合并行请求全部完成的场景;Promise.race()适合超时控制;Promise.allSettled()适合需要知道每个请求结果的批量场景。实际开发中,Promise 常用于接口请求封装、多接口并行、超时控制、Loading 状态管理、图片预加载等场景。
另外,
async/await是 Promise 的语法糖,它让代码更像同步写法,可读性更好。我通常优先用async/await,但在并行场景里还是会配合Promise.all()使用,避免把并行请求变成串行,损失性能。当然 Promise 也有缺点,比如无法取消、无法获取中间进度、没有
.catch()的话内部错误容易被吞掉,这些在使用时需要注意。
十、精简版面试回答
如果时间比较短,可以这样答:
Promise 是 ES6 用于处理异步的解决方案,核心是用一个对象表示异步操作的最终结果,状态有
pending、fulfilled、rejected,且状态一旦确定不可改变。
它解决了回调地狱的问题,通过链式.then()让异步代码更清晰。
常用方法有.then()、.catch(),静态方法有Promise.all()、Promise.race()、Promise.allSettled()等,分别适用于并行等待、竞速、批量结果收集等场景。
实际上我更多是配合async/await使用,让代码更接近同步写法,但并行场景还是会用Promise.all()保持并发性能。
十一、一句话总结
面试官真正想听的是:
- 你是否理解 Promise 解决了什么问题
- 你能不能说清楚 三种状态和不可逆性
- 你是否熟悉 常用方法和静态方法
- 你能不能结合 实际场景 来说使用价值
- 你有没有意识到 async/await 和 Promise 的关系
更多推荐



所有评论(0)