赞
踩
在 ES6 出来之后,有很多有关于 Promise 的讲解,文件也有很多经典的书籍讲解 Promise
虽然等你学会 Promise 之后,会觉得 Promise 不过如此,但是第一次接触后 Promsie 还是很不好理解
那么我们就以一个实际的例子作为切入口
function request(cb) {
// 模拟网络请求
let flag = Math.random() <= 0.5 ? true : false
setTimeout(() => {
cb(flag, flag ? '成功的数据' : '失败的信息')
}, 1000)
}
console.log('发起请求')
request((status, msg) => {
console.log(status, msg)
})
request((s1, m1) => {
request((s2, m2) => {
request((s3, m3) => {
// 出现了回调地狱
}
})
})
使用这种回调函数存在的弊端:
所以,需要一种异步操作的规范,而 Promise 生来就是为了解决异步操作的问题
Promise
是一个类,可以翻译为承诺、期约
当通过new
创建Promise
实例时,需要传入一个回调函数,我们称之为executor
resolve
、reject
resolve
回调函数时,会执行 Promise 对象的then
方法传入的回调reject
回调函数时,会执行 Promise 对象的catch
方法传入的回调Promise
是一个状态机,分为 3 种状态:
pending
:待定状态,执行了 executor 后,处于该状态fulfilled
:兑现状态,调用resolve()
后,Promise 的状态更改为 fullfilled,且无法再次更改rejected
:拒绝状态,调用reject()
后,Promise 的状态更改为 rejected,且无法再次更改function request() {
const flag = Math.random() <= 0.5 ? true : false
return new Promise((resolve, reject) => {
setTimeout(() => {
if (flag) {
resolve('成功的消息')
return
}
reject('失败的消息')
}, 2000)
})
}
console.log('请求开始')
request()
.then(msg => console.log(msg), err => console.log(err))
resolve 传入的参数情况:
const newPromise = new Promise((resolve, reject) => {
resolve('success')
})
new Promise((resolve, reject) => {
// 当前 Promise 的状态由传入的 Promise 去决定
resolve(newPromise)
})
.then(res => {
console.log('res', res)
})
.catch(err => {
console.log('err', err)
})
new Promise((resolve, reject) => {
// 如果 resolve 传入的是对象,且该对象实现了 then 方法
// 则该 Promise 的状态由 then 方法决定
resolve({
then(resolve, reject) {
reject('error')
},
})
})
.then(res => {
console.log('res', res)
})
.catch(err => {
console.log('err', err)
})
通过then
方法可以对 Promise 中的resolve
进行处理。then
方法的返回值是一个 Promise 实例
new Promise(resolve => {
resolve('你好')
}).then(res => console.log(res)) // 会打印你好
多次调用 then 方法
同一个 Promise 实例可以调用多个then
方法,当 Promise 中resolve
被回调时,所有 then 方法传入的回调函数都会被调用
const promise = new Promise(resolve => {
resolve('你好')
})
// 同时调用
promise.then(res => console.log(res))
promise.then(res => console.log(res))
promise.then(res => console.log(res))
then 方法传入的回调函数可以有返回值
如果返回的是普通值,那么这个普通值将作为一个新的 Promise 的resolve
的值
const promise = new Promise(resolve => {
resolve('你好')
})
promise.then(() => 'then').then(res => console.log(res)) // 打印 then
// promise.then(() => 'then') 相当于
promise.then(() => {
return new Promise(resolve => {
resolve('then')
})
})
如果返回的是 Promise,那么就可以再次调用then
方法
const promise = new Promise(resolve => {
resolve('你好')
})
promise
.then(() => {
return new Promise(resolve => {
setTimeout(() => {
resolve('success')
}, 2000)
})
})
.then(msg => {
// 2 秒后打印 success
console.log(msg)
})
如果返回的是一个对象,并且该对象实现了 thenable,该 then 函数有两个参数resolve
、reject
,则 resolve 的将会传递给下一个 Promise。
const promise = new Promise(resolve => {
resolve('你好')
})
promise
.then(() => {
return {
then(resolve) {
return resolve('success')
},
}
})
.then(msg => {
// 打印 success
console.log(msg)
})
除了then
方法的第二个参数来捕获reject
错误之外,还可以通过catch
方法,catch 返回一个 Promise
const promise = new Promise((resolve, reject) => {
reject('error')
})
promise.then(undefined, err => {
// 打印 error
console.log(err)
})
// 但是这种写法不太符合`promise/a+`规范
promise.catch(err => {
// 打印 error
console.log(err)
})
// 下面是符合`promise/a+`规范的写法
promise
.then(() => {})
.catch(err => {
console.log(err)
})
// 已知 then 方法也可以返回一个 promise,因此在 then 后面追加 catch,以此来捕获 rejected 的情况,更加具有语义化
catch
方法也是可以多次调用的,只要 Promise 实例的状态为 rejected,那么就会调用catch
方法
const promise = new Promise((resolve, reject) => {
reject('error')
})
// 这两个 catch 都会调用
promise.catch(err => {
console.log(err)
})
promise.catch(err => {
console.log(err)
})
catch 方法的返回值
catch 方法也会返回一个Promise
实例,返回值的情况:
resolve
的参数finally 是 ES9(ES2018) 新增的一个特性,无论一个Promise
实例是fulfilled
或rejected
,finally
都会执行。
finally 不接收参数。
const promise = new Promise((resolve, reject) => {
reject('error')
})
promise
.then(res => {
console.log('res:', res)
})
.catch(err => {
console.log(('err', err))
})
.finally(() => {
console.log('finally code execute')
})
如果我们想要将一个现成的数据转换为一个 Promise 实例,那么你可以这么做:
const foo = {
name: 'alex',
}
function bar(obj) {
return new Promise(resolve => {
resolve(obj)
})
}
bar(foo).then(res => {
console.log(res)
})
还可以直接类方法resolve()
,使用Promise.resolve()
相当于new Promise(resolve => { resolve() })
function bar(obj) {
return Promise.resolve(obj)
}
resolve 参数形态:
与Promise.resolve()
方法逻辑基本相同,只不过Promise.reject()
相当于创建一个 Promise 实例,并且 rejected 了
Promise.reject('error').catch(error => {
console.log('error', error)
})
注意:与Promise.resolve()
不同的是,Promise.reject()
无论传递什么参数都会原样输出
Promise.reject(
new Promise(resolve => {
resolve('hello')
})
).catch(err => {
// 原样打印 Promise 实例
console.log('err', err)
})
Promise.all()接收一个
Promise[],返回一个
Promise实例,当所有的 Promise 执行完毕并且都是
fulfilled时,该实例的状态才会变为
fulfilled,只要队列中有一个实例的状态是
rejected,那么该实例的状态也会变为
rejected
如果 Promise 队列中所有的实例状态都是fulfilled
,那么Promise.all()
返回的实例的状态就会变为fulfilled
,并且resolve()
的参数是一个数组,按照顺序放置队列中每个 Promise 成功后的结果
let i = 0
function genPromise() {
return new Promise(resolve => {
resolve(`success${(i = i + 1)}`)
})
}
const promiseArr = [genPromise(), genPromise(), genPromise()]
Promise.all(promiseArr).then(res => {
// [ 'success1', 'success2', 'success3' ]
console.log('res', res)
})
如果队列中 Promise 实例有一个是rejected
,那么Promise.all()
返回的实例就会变为rejected
状态,并且reject()
参数是队列中第一个rejected
的返回值
const promiseArr = [
genPromise(),
new Promise((resolve, reject) => {
reject('error1')
}),
new Promise((resolve, reject) => {
reject('error2')
}),
]
Promise.all(promiseArr)
.then(res => {})
.catch(err => {
// error 1
console.log(err)
})
all
方法是有缺陷的,如果在 Promise 队列中有一个状态是 rejected,那么我们就无法获取到其他 fullfilled 以及 pending 的 Promise 实例了。
针对这一情况,在 ES11(ES2020) 中新增了一个 API,Promise.allSettled()
fulfilled
,并且只会是fulfilled
const promiseArr = [
new Promise((resolve, reject) => {
resolve('success1')
}),
new Promise((resolve, reject) => {
reject('error')
}),
new Promise((resolve, reject) => {
resolve('success2')
}),
]
Promise.allSettled(promiseArr).then(res => {
// res [
// { status: 'fulfilled', value: 'success1' },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 'success2' }
// ]
console.log('res', res)
})
Promise.race()
同样接收一个 Promise 队列,返回一个 Promise 实例。该方法会对队列任务完成情况进行监听,如果某一个任务最先完成fulfilled/rejected
,那么返回的实例的状态也会变成对应的fulfilled/rejected
,同时获取到最先完成的结果
const promiseArr = [
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success1')
}, 1000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success2')
}, 3000)
}),
]
Promise.race(promiseArr)
.then(res => {
console.log('res', res)
})
.catch(err => {
console.log('err', err)
})
// 最终打印 res success1
// 如果第二个任务最先完成,那么就会打印 err error
Promise.any()
是 ES12 新增的特性,和Promise.race()
类似,区别在于:
fulfilled
状态,才会决定返回 Promise 实例的状态rejected
状态,那也需要等到所有执行完毕后才会决定返回的 Promise 实例的状态const promiseArr = [
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success1')
}, 2200)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success2')
}, 3000)
}),
]
Promise.any(promiseArr)
.then(res => {
console.log('res', res)
})
.catch(err => {
console.log('err', err)
})
// 遇到第一个 fulfilled,就会转变返回的 Promise 实例的状态
// 如果所有的都是 rejected,那么只有所有执行完毕后,返回的 Promise 实例才会转变
// 并且会抛出一个错误:[AggregateError: All promises were rejected]
简单理解来说,Promise.any()
会等待第一个fulfilled
的 Promise ,如果队列中没有fulfilled
,那么就会返回一个错误
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。