Promise详解
ES6 新增 Promise
介绍
Promise 是异步编程的一种解决方案:
从语法上讲,promise是一个对象,从它可以获取异步操作的消息;
从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
1.为什么需要有Promise?
promise主要解决的问题:
- 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
- promise可以支持多个并发的请求,获取并发请求中的数据
- 这个promise可以解决异步的问题,本身不能说promise是异步的
补充一下,什么是回调函数?
就是我给你传一个函数,你反过来调用我
![]()
一般来说我们会碰到的回调嵌套都不会很多,一般就一到两级,但是某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,这种情况俗称——回调地狱。
// 当参数a大于10且参数fn2是一个方法时 执行fn2
function fn1(a, fn2) {
if (a > 10 && typeof fn2 == 'function') {
fn2() // 回调函数
}
}
fn1(11, function() {
console.log('this is a callback')
})
2.Promise是什么?怎么使用?
-
Promise 是一个类,字面意思:承诺、期约
-
通过 new 可以创建一个 Promise 对象,并且需要传入回调函数(executor)
这个回调函数会被立即执行,并且会传入另外两个回调函数 resolve、reject
当我们调用resolve回调函数时,会执行Promise对象的then方法传入的第一个回调函数,当调用reject的时候,会执行第二个回调
const promise = new Promise((resolve, reject) => {
resolve("success message")
// reject("failure")
})
promise.then(res => {
console.log(res);
}, err => {
console.log(err);
})
Promise的三种状态
Promise使用过程,我们可以将它划分成三个状态:
pending:待定,初始状态,既没有被兑现,也没有被拒绝;当执行executor中的代码时,处于该状态;
fulfilled:已兑现, 意味着操作成功完成;执行了resolve时,处于该状态; (也有的地方叫resolved状态)
rejected:已拒绝,意味着操作失败; 执行了reject时,处于该状态;
new Promise((resolve, reject) => {
// pending待定
resolve() // fulfilled(已完成)
reject() // rejected(已拒绝)
}).then(res => {
console.log(res);
}, err => {
console.log(err);
})
注意:Promise的状态一旦确定,就不可更改,只有两种状态改变:
pending -> fulfilled pending -> rejected
另外我们如果抛出异常,状态也是rejected,会回调then的第二个参数
new Promise((resolve, reject) => { throw new Error("异常") }).then(res => { console.log(res); }, err => { console.log(err); // Error: 异常 })
resolve不同值的区别
resolve(参数):resolve的参数,三种情况
-
参数是普通值(数值/字符串/普通对象/undefined),状态变化 pending -> fulfilled
-
参数又是一个Promise对象,那么这个新Promise会决定原Promise的状态
const newPromise = new Promise((resolve, reject) => { resolve("hahhaha") // reject() }) new Promise((resolve, reject) => { resolve(newPromise) // 状态由newPromise决定 }).then(res => { console.log(res); // hahhaha }, err => { console.log(err); }) -
参数是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据 then方法的结果来决定Promise的状态
new Promise((resolve, reject) => { const obj = { then: function(resolve, reject) { resolve("resolve message") // reject() } } resolve(obj) }).then(res => { console.log(res); }, err => { console.log(err); })
Promise对象方法
then,catch,finally
then方法
1. 两个参数
then方法是Promise对象上的方法,实际上是放在Promise的原型上的:Promise.prototype.then
then方法接收两个参数:
- fulfilled的回调函数:当状态变成fulfilled时会回调的函数
- reject的回调函数:当状态变成reject时会回调的函数
2. 多次调用
同一个Promise是可以被多次调用then方法的,当resolve方法被回调时,所有的then方法传入的回调函数都会被调用
const promise = new Promise((resolve, reject) => {
resolve("success")
})
// 注意这不是链式调用
promise.then(res1 => {
console.log(res1); // success
})
promise.then(res2 => {
console.log(res2); // success
})
promise.then(res3 => {
console.log(res3); // success
})
3. then的返回值
then方法本身是有返回值的,它的返回值是Promise
- 如果我们then的第一个回调返回的是一个普通值(数值/字符串/普通对象/undefined), 那么这个普通的值会被作为一个新的Promise的resolve值
const promise = new Promise((resolve, reject) => {
resolve("success")
})
let newPromise = promise.then(res => {
return "aaa"
})
console.log(newPromise);
所以我们可以进行链式调用
promise.then(res => {
return "aaa"
}).then(res => {
console.log(res); // "aaa"
return "bbb"
}).then(res => {
console.log(res); // "bbb"
})
- 如果返回的是一个Promise
那么这个Promise会决定下一个then返回的promise的状态
promise.then(res => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1111)
}, 3000)
// reject('err')
})
}).then(res => {
console.log(res); // 3秒后打印 1111
}, err => {
console.log(err);
})
- 如果返回的是一个对象, 并且该对象实现了then方法
promise.then(res => {
return {
then: function(resolve, reject) {
resolve(2222)
}
}
}).then(res => {
console.log(res) // 222
})
其实一样的,既然then返回一个promise,那就跟前面一样的处理,也就是可以继续链式调用then去处理,自己多尝试各种情况看看就都可以理解了
catch方法
catch方法也是Promise对象上的一个方法:它也是放在Promise的原型上的 Promise.prototype.catch()
- catch方法传入错误(拒绝)捕获的回调函数
- catch也可以多次调用
- 我们可以把catch方法理解为 then 方法的语法糖
const promise = new Promise((resolve, reject) => {
reject("reject message")
})
promise.catch(err => {
console.log(err);
})
// 等价于
promise.then(undefined, err => {
console.log(err);
})
- 注意下面两种情况,catch的处理
const promise = new Promise((resolve, reject) => {
reject("err message")
// 如果这里调用reject,也就是这个promise的状态是rejected
})
promise.then(res => {
return new Promise((resolve, reject) => {
reject("reject2 message")
})
}).catch(err => {
console.log(err); // err message
})
const promise = new Promise((resolve, reject) => {
resolve("aaa") // 如果这里调用resolve,fulfilled状态
})
promise.then(res => { // 先调用 then 的第一个回调
return new Promise((resolve, reject) => {
reject("reject2 message")
// then返回的promise的状态是rejected
})
}).catch(err => {
console.log(err); // reject2 message catch可以捕获到
})
所以说catch会处理首次出现拒绝状态的Promise
- catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法
const promise = new Promise((resolve, reject) => {
reject("111")
})
promise.then(res=>{
console.log(res);
}).catch(err => {
console.log(err); // "111"
return "222" // 这个catch返回的promise的状态为 fulfilled
}).then(res=>{
console.log(res); // 222
}).catch(err => {
console.log(err);
})
finally方法
finally是在ES9(ES2018)中新增的一个特性:无论Promise对象变成fulfilled还是reject状态,最终都会被执行,所以finally也不需要接收参数
promise.then(res=>{
console.log(res);
}).catch(err => {
console.log(err);
}).finally(() => {
console.log("finally"); // "finally"
})
finally 也会返回一个promise,但是一般我们不会继续再后面做处理了
Promise类方法
也就是直接通过Promise调用的方法,不需要创建实例
Promise.resolve
直接把某个内容转成Promise来使用
Promise.resolve的用法相当于new Promise,并且执行resolve操作
Promise.resolve("hello")
// 等价于
new Promise((resolve) => {
resolve("hello")
})
resolve的参数跟前面一样的三种,普通的值,Promise,有then方法的obj
Promise.reject
会将Promise对象的状态设置为reject状态
Promise.reject("hello")
// 等价于
new Promise((resolve, reject) => {
reject("hello")
})
注意:Promise.reject无论传入的参数是什么形态,都是会直接作为reject状态的参数
const promise = Promise.reject(new Promise((resolve, reject) => {
resolve("123")
}))
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err) // err: Promise {<fulfilled>: '123'}
})
Promise.all
将多个Promise包裹在一起形成一个新的Promise,新的Promise状态由包裹的所有Promise共同决定:
-
当所有的Promise状态变成 fulfilled 状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组
const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(111) }, 1000) }) const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve(222) }, 2000) }) const p3 = new Promise((resolve, reject) => { setTimeout(() => { resolve(333) }, 3000) }) Promise.all([p1, p2, p3]).then(res => { console.log(res); // [ 111, 222, 333 ] }).catch(err => { console.log(err); }) -
当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数
... const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject(222) }, 2000) }) ... Promise.all([p1, p2, p3]).then(res => { console.log(res); }).catch(err => { console.log(err); // 222 })
Promise.allSettled
ES11(ES2022)新增
该方法会在所有的Promise都有结果(无论是fulfilled还是reject)后才会有最终的状态,并且返回的Promise的状态一定是fulfilled
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 3000)
})
Promise.allSettled([p1, p2, p3]).then(res => {
console.log("res:", res); // 执行的是这里
}).catch(err => {
console.log("err:", err);
})
打印的结果是一个数组,存放每一个Promise的结果
status:状态,value:值
Promise.race
race:竞赛,这个方法可以理解为Promise的竞赛
当最先执行完的事件执行完之后,就直接返回该promise对象的值。如果第一个promise对象状态变成fulfilled,那自身的状态变成了fulfilled;反之第一个promise变成rejected,那自身状态就会变成rejected。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 500) // 先执行完
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 3000)
})
Promise.race([p1, p2, p3]).then(res => {
console.log("res:", res);
}).catch(err => {
console.log("err:", err); // err: 222
})
Promise.any
ES12新增,和race方法类似
any方法会等到第一个fulfilled状态,才会决定新Promise的状态
如果所有的Promise都是reject的,那么会报一个AggregateError的错误
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(111)
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 2000)
})
Promise.any([p1, p2]).then(res => {
console.log("res:", res);
}).catch(err => {
console.log("err:", err); // err: 222
})
// 输出:
// err: AggregateError: All promises were rejected
// err.errors可以拿到全部错误信息