promise 是什么
- 抽象表达:
Promise
是JS中进行异步变成的新的解决方案 - 具体表达:
- 从语法上来说:
Promise
是一个构造函数 - 从功能上来说:
promise
对象用来封装一个异步操作并可以获取其结果
- 从语法上来说:
promise与传统的回调对比
- 传统回调模式是回调地狱写法,非常不便于书写及阅读,使代码更臃肿,而
promise
支持链式调用,代码可以从上往下发展 - 配合使用
async
、await
会让异步代码变为同步代码 - 传统回调模式指定回调时,只能是在任务启动前,而
promise
可以在任务启动后才指定回调,例如可以在等多长时间后才指定回调处理 promise
可以对同一个任务指定多个回调
promise的一些关键问题
1. 如何改变promise的状态?
resolve(value)
:如果当前状态是pending
就会变成resolved
reject(reason)
:如果当前状态是pending
就会变成rejected
- 抛出异常
throw new Error('reason')
:如果当前状态是pending
就会变成rejected
2. 对一个 promise 指定多个成功/失败的回调,是否都会执行
答:当 promise
的状态改变后,都会执行对应成功/失败的多个回调
const p = new Promise((resolve, reject) => {
resolve()
})
p.then(res => {})
p.then(res => {})
p.then(res => {})
// ...
3. 改变 promise 状态和指定回调函数谁先谁后
- 都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调
- 如何先改变状态在指定回调?
- 在执行器中调用
resolve()
、reject
改变状态 - 延迟更长时间再调用
then()
- 在执行器中调用
const p = new Promise((resolve, reject) => {
resolve()
})
setTimeout(() => {
p.then(value => {})
}, 5000)
4. promise.then()
返回的新 promise 的结果状态由什么决定
- 简单表达:由
then()
指定的回调函数执行的结果决定 - 详细表达
- 如果抛出异常:新
promise
的状态变为rejected
,reason
为抛出的异常 - 如果返回的是非
promise
的任意值,新promise
的状态变为resolved
,value
为返回的值,什么都不返回的情况,函数会返回undefined
,undefined
也是非promise
的值 - 如果返回的是一个新的
promise
,此promise
的结果就会成为新promise
的结果
- 如果抛出异常:新
5. 回调函数是同步还是异步执行
答:promise
的回调函数属于异步任务,会在同步任务之后执行。但不是正常的异步任务,而是 微任务(microtask)
// 定时器回调是 宏任务
setTimeout(() => {
console.log('定时器回调')
})
// promise回调是 微任务
new Promise((resolve, reject) => {
resolve()
}).then(res => {
console.log('promise回调')
})
// 执行结果如下:微任务会比宏任务先执行
// promise回调
// 定时器回调
6. promise 异常传透?
当使用 promise
的链式调用时(p.then().then() ...
),可以在最后指定失败的回调(.catch(() => {})
),因为前面任何操作出现了异常,都会传到最后失败的回调中处理
// 第一层把 promise 的状态改为 rejected 失败状态后,下一层如果没写失败回调,则继续抛出异常,就这样一层一层的往下传
new Promise((resolve, reject) => {
reject('错误')
}).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).catch(reason => {
console.log(reason)
})
7. 如何终端 promise 链?
在回调函数中返回一个 pending
状态的 promise
对象
new Promise((resolve, reject) => {
reject('错误')
}).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).then(
value => 'ok',
// 不写失败回调,内部会默认这样的写法
reason => {throw reason}
).catch(reason => {
// 到了这一步后,如果后面还有回调,但是需要再这里终止 promise 链,
// × 返回 失败的 promise 后还是会进入到下一个失败的回调
// return Promise.reject('失败')
// × 抛出异常后还是会进入到下一个失败的回调
// throw '失败'
// √ 返回一个 pending 状态的 promise
return new Promise(() => {})
}).then(
value => {
console.log('成功回调')
},
reason => {
console.log('失败回调')
}
)