promise是异步编程的解决方案
1. 什么时候用到promise?
一般情况下是有异步操作时,对其进行封装,常见的场景就是网络请求,一个网络请求完成后会传给下一个网络请求参数去继续请求,如果当这个回调比较多且数据处理比较麻烦时,就会让我们陷入回调地狱
2. 状态
等待态(Pending):比如正在进行网络请求时,或者定时器还没到时间
执行态/满足状态(Fulfilled): 当我们主动回调了resolve,就会处于该状态,并且会回调.then()
拒绝态(Rejected):当我们主动回调了reject,就会处于该状态,并且会回调.catch()
一旦Promise 被 resolve 或 reject,不能再迁移至其他任何状态(即状态 immutable)。
3. 使用
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ test: 1 })
reject({ test: 2 })
}, 1000)
}).then(data => {
console.log(data)
}).catch(err=>{
console.log(err)
})
new Promise时--> 保存了一些状态信息 ,执行传入的函数
在执行传入的函数时,会传入两个参数resolve, reject 本身又是函数
成功时,调用resolve,resolve被调用时,触发then,then接收的参数就是resolve传入的参数
失败时,调用reject,reject被调用时,触发catch,catch接收的参数是reject传入的参数
但是呢,then是可以传入两个参数的,第一个也就是上面的处理resolve的函数,第二个就可以是处理reject的函数,下面的写法跟上面的大同小异:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ test: 1 })
reject({ test: 2 })
}, 1000)
}).then(data => {
console.log(data)
}, err=>{
console.log(err)
})
4. 链式调用
new Promise((resolve, reject) => {
// 异步操作1
setTimeout(() => {
resolve('111')
}, 1000)
}).then(data => {
console.log(data)
// 异步操作2,通过返回一个Promise,实现链式调用
return new Promise((resolve, reject) => {
resolve('222')
})
}).then(data => {
console.log(data)
})
可以简化:
new Promise((resolve, reject) => {
// 异步操作1
setTimeout(() => {
resolve('111')
}, 1000)
}).then(data => {
console.log(data)
// 异步操作2
return Promise.resolve('222')
// Promise.reject('失败可以调用这个')
}).then(data => {
console.log(data)
})
还可以简化:
new Promise((resolve, reject) => {
// 异步操作1
setTimeout(() => {
resolve('111')
}, 1000)
}).then(data => {
console.log(data)
// 异步操作2, 直接return,其内部会自动将其包装成Promise
return '222'
}).then(data => {
console.log(data)
})
其中我们用throw '错误信息' 也可以手动抛出异常,在catch中可以捕获
4. Promise.finally()
es9新增,作用类似于ajax的complete,即异步完成之后执行的代码,无论Promise运行成功还是失败
function doSomething() {
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally(() => {
// finish here!
});
}
5. Promise.all
经常会碰到这样的需求:我们的处理必须等待两个网络请求返回成功后才能进行,这时候我们可能会用两个变量来判断请求是否完成,但是呢,promise提供了一个方法all可以轻松的帮我们解决这个问题
它需要一个 promise 的数组作为其参数(严格来说可以是任何可迭代对象,但通常都是数组)并返回一个新的 promise。
当所有给定的 promise 都被处理并以数组的形式呈现其结果时,新的 promise 也就被 resolve。
Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
]).then(alert); // 1,2,3 当 promise 就绪:每一个 promise 即成为数组中的一员
请注意,它们的相对顺序是相同的。即使第一个 promise 需要很长的时间来 resolve,但它仍然是结果数组中的第一个。
常见技巧是将一组作业数据映射到一个 promise 数组,然后再将它们封装进 Promise.all
。
6. Promise.race
语法和all()一样,但是返回值有所不同,race根据传入的多个Promise实例,只要有一个实例resolve或者reject,就只返回该结果,其他实例不再执行。(比谁先执行完,谁先执行完就用谁的结果,其它的都不再执行。race:赛跑比速度)
Promise.race([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
]).then(value=>{
console.log(value)
} // 3 第三个定时器先执行完成