promise详解
Promise详解
ES6 新增 Promise
介绍
Promise 是异步编程的一种解决方案:
从语法上讲,promise是一个对象,从它可以获取异步操作的消息;
从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
1.为什么需要有Promise?
promise主要解决的问题:
- 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
- promise可以支持多个并发的请求,获取并发请求中的数据
- 这个promise可以解决异步的问题,本身不能说promise是异步的
补充一下,什么是回调函数?
就是我给你传一个函数,你反过来调用我
一般来说我们会碰到的回调嵌套都不会很多,一般就一到两级,但是某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,这种情况俗称——回调地狱。
// 当参数a大于10且参数fn2是一个方法时 执行fn2 |
2.Promise是什么?怎么使用?
Promise 是一个类,字面意思:承诺、期约
通过 new 可以创建一个 Promise 对象,并且需要传入回调函数(executor)
这个回调函数会被立即执行,并且会传入另外两个回调函数 resolve、reject
当我们调用resolve回调函数时,会执行Promise对象的then方法传入的第一个回调函数,当调用reject的时候,会执行第二个回调
const promise = new Promise((resolve, reject) => { |
Promise的三种状态
Promise使用过程,我们可以将它划分成三个状态:
pending:待定,初始状态,既没有被兑现,也没有被拒绝;当执行executor中的代码时,处于该状态;
fulfilled:已兑现, 意味着操作成功完成;执行了resolve时,处于该状态; (也有的地方叫resolved状态)
rejected:已拒绝,意味着操作失败; 执行了reject时,处于该状态;
new Promise((resolve, reject) => { |
注意: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) => { |
3. then的返回值
then方法本身是有返回值的,它的返回值是Promise
- 如果我们then的第一个回调返回的是一个普通值(数值/字符串/普通对象/undefined), 那么这个普通的值会被作为一个新的Promise的resolve值
const promise = new Promise((resolve, reject) => { |
所以我们可以进行链式调用
promise.then(res => { |
- 如果返回的是一个Promise
那么这个Promise会决定下一个then返回的promise的状态
promise.then(res => { |
- 如果返回的是一个对象, 并且该对象实现了then方法
promise.then(res => { |
其实一样的,既然then返回一个promise,那就跟前面一样的处理,也就是可以继续链式调用then去处理,自己多尝试各种情况看看就都可以理解了
catch方法
catch方法也是Promise对象上的一个方法:它也是放在Promise的原型上的 Promise.prototype.catch()
- catch方法传入错误(拒绝)捕获的回调函数
- catch也可以多次调用
- 我们可以把catch方法理解为 then 方法的语法糖
const promise = new Promise((resolve, reject) => { |
- 注意下面两种情况,catch的处理
const promise = new Promise((resolve, reject) => { |
const promise = new Promise((resolve, reject) => { |
所以说catch会处理首次出现拒绝状态的Promise
- catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法
const promise = new Promise((resolve, reject) => { |
finally方法
finally是在ES9(ES2018)中新增的一个特性:无论Promise对象变成fulfilled还是reject状态,最终都会被执行,所以finally也不需要接收参数
promise.then(res=>{ |
finally 也会返回一个promise,但是一般我们不会继续再后面做处理了
Promise类方法
也就是直接通过Promise调用的方法,不需要创建实例
Promise.resolve
直接把某个内容转成Promise来使用
Promise.resolve的用法相当于new Promise,并且执行resolve操作
Promise.resolve("hello") |
resolve的参数跟前面一样的三种,普通的值,Promise,有then方法的obj
Promise.reject
会将Promise对象的状态设置为reject状态
Promise.reject("hello") |
注意:Promise.reject无论传入的参数是什么形态,都是会直接作为reject状态的参数
const promise = Promise.reject(new Promise((resolve, reject) => { |
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) => { |
打印的结果是一个数组,存放每一个Promise的结果
status:状态,value:值
Promise.race
race:竞赛,这个方法可以理解为Promise的竞赛
只要有一个Promise变成fulfilled状态, 那么就结束,并使用这个promise的结果
const p1 = new Promise((resolve, reject) => { |
Promise.any
ES12新增,和race方法类似
any方法会等到第一个fulfilled状态,才会决定新Promise的状态
如果所有的Promise都是reject的,那么会报一个AggregateError的错误
const p1 = new Promise((resolve, reject) => { |