Promise是面试官经常问的一个问题
也算是基础知识点,如果这个不了解的话,他可能会认为你还不能快速的进入项目开发当中来。
1 什么是Promise
Promise是一种异步编程的解决方案,为了解决回调地狱的问题。 回调地狱就是一个异步请求套着另外一个异步请求,依赖其执行结果层层嵌套。Promise是一个对象,从它中可以获取异步操作的消息。
2 Promise的特点
Promise对象是一个构造函数,用来生成Promise实例。
var promise = new Promise(executor){
}
正如上,构建一个Promise对象时,需要传入一个executor函数,主要的业务流程在executor中执行。
Promise构造函数执行时,立即调用executor函数,其中resolve和reject两个函数作为参数传递给executor。resolve和reject调用时,分别将Promise状态由 pengding => fulfilled pending => rejected 且状态一旦改变,则不会再次改变。
executor函数中调用resolve函数,则触发Promise.then设置的回调函数,调用reject函数,则触发Promise.catch设置的回调函数。
3 同步还是异步
Promise是用来管理异步编程的,它本身是同步的。 例:
let p1 = new Promise(() => {
setTimeout(() => {
console.log(1)
}, 1000)
console.log(2)
})
console.log(3)
则执行顺序为 2 3 1
let p1 = new Promise((resolve, reject) => {
console.log(1)
resolve('了解')
console.log(2)
})
p1.then(result => {
console.log('成功' + result)
}, reason => {
console.log('失败' + result)
})
console.log(3)
则上述执行顺序应为 1 2 3 成功了解 解析: 开始先执行第一遍的所有同步代码,1 2 遇到then的时候是微任务所以继续往下进行。所以输出3 。3执行完后,去清空微任务队列。打印 “成功了解”
例:
new Promise(resolve => {
resolve(a)
// 报错
}).then(result => {
console.log(`成功: ${result}`)
return result * 10
},reason => {
console.log(`失败: ${reason}`)
// 执行这句时没有返回异常或者返回一个失败的Promise实例,会继续执行下个then
}).then(result => {
console.log(`成功:${result}`)
}, reason => {
console.log(`失败: ${reason}`)
})
输出顺序: 失败:referenceError a is not defined 成功 undefined
4 then中含有return的情况
当then的回调函数中存在return值的时候:
.then(() => return 2)
.then(result => console.log(result)) // 2
.then(() => return new Promise())
.then(result => console.log(result)) // 上面的 new Promise
所有这里的return 和 resolve差不多。当then中没有return也会返回一个Promise新实例供下一个then使用。
5 Promise常用的方法
5.1 Promise.resolve()
Promise.resolve('foo')就等价于 new Promise(resolve => resolve('foo'))
Promise.resolve的参数有以下4中情况
1.参数为一个Promise实例
如果参数是Promise实例,则Promise.resolve将原封不动的返回该实例。
const p1 = new Promise(function (resolve, reject){
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise((resolve, reject){
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => console.log(result)).catch(err => console.log(err))
p1 3秒后变为reject, p2 1秒后就变为 P1, 所以P2.then针对的是P1的状态变化。最后应为err 触发catch
2.参数不是具有then的对象,或者根本不是对象
Promise.resolve('success').then(value => {
console.log(value) // success
}, function(value) {
})
参数会传给then回调函数
3.不带任何参数
Promise.resolve方法调用时,如果不带参数,则直接返回一个resolve状态的Promise对象
如果希望获得一个Promise对象,则可以直接调用Promise.resovle()
Promise.resolve().then(() => console.log('two'))
4.参数是thenable对象
thenable对象值得是具有then方法的对象, Promise.resolve方法会将这个对象转为Promise对象,然后立即执行thenable对象的then方法。
let thenable = {
then: function(resolve, reject) {
resolve()
}
}
let P1 = Promise.resolve(thenable)
P1.then(function(value) {console.log(value)}) // 42
5.2 Promise.reject
返回一个带有拒绝原因的Promise对象
new Promise((resolve, reject) => reject(new Error('出错了')))
// 等价于
Promise.reject(new Error('出错了'))
5.3 Promise.all
生成并返回一个新的Promise对象,它可以使用Promise实例的所有方法。
参数为Promise对象组成的数组,等所有的Promise对象都变成resolve的时候,该方法才返回。
let p1 = Promise.resolve(1)
let p2 = new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 1000)
})
let p3 = Promise.resolve(3)
Promise.all([p3, p2, p1]).then(result => {
console.log(result) // [3, 2, 1] 按照顺序返回
})
注意: 参数中任一个Promise为reject,则Promise.all停止
扩展:项目中调用接口时,可以自己套一层Promise
return new Promise((resolve, reject) => {
this.$service.network.get(url).then(res => {
resolve(res)
})
})
5.4 Promise.allSettled
与Promise.all类似,唯一不同点是不会短路。纵使某一个Promise对象reject,但不影响进程,最后我们可以筛选出成功的Promise(filter)
5.5 Promise.race
Promise.race与all的用法一样,接收一个Promise对象数组为参数
区别:
all是所有对象都变为FulFilled或者rejected状态,才进行then回调函数
race是只有存在一个Promise的状态变为FulFilled 或者 rejected就进行then函数回调。
5.6 Promise.prototype.finally
ES9新增finally方法返回Promise,在Promise结束时,无论结果是fulfilled或者是rejected。都会执行的回调函数。
这为Promise无论成功与否都需要执行的代码提供了一种方式,避免了then和catch中各写一次的情况。
this.loading = true
request().then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
.finally(() => {
this.loading = false
})
只有Promise状态发生变化后,才会执行finally。且finally方法的回调函数不接受任何参数,与状态无关。
new Promise(() => {
}).finally(() => {
console.log(111)
})
// 此时的状态一直是pending状态,所有finally不会执行的
5.7 Promise.any
最先一个resolve出来的,只有当所有的Promise对象都rejected。Promise.any才会输出reject。注意与Promise.race的区别