Promise
一. promise的基本语法:
let p1 = new Promise((resolve, reject) => {
// resolve和reject是Promise内提供的2个函数, 用于回调返回结果到外面
resolve('111') // 触发.then()小括号里函数体执行
reject('222') // 触发.catch()小括号里函数体执行
}).then(res=>{
console.log(res)
// res = 111
}).catch(err=>{
console.log(err)
// err = 111
})
二. promise的状态和值:
promise的状态
pending: 准备; resolved(或者fulfilled) 成功; rejected: 失败
准备:new实例化后, Promise对象(pending准备状态)
成功:当Promise内代码执行了resolve, 会导致所在的Promise对象 变成 fulfilled成功状态
失败:当Promise内代码执行了reject, 会导致所在的Promise对象 变成 rejected失败状态
promise的值
resolve(值),这个值会自动传递给then
reject(值),这个值会自动传递给catch
三.then的格式及执行逻辑
then方法的作用是为Promise对象添加状态改变时的回调函数。
下面从其调用格式,执行逻辑及返回值三个方面来介绍
1.then的调用格式
它有两个参数,每个参数都是函数。 第二个参数是可选的。
// p 是一个promise对象
p.then(函数1[,函数2])
它的两个参数都是函数。
- 第一个参数是resolved状态的回调函数。当p的状态从pending变成了resolved,函数1会执行。
- 第二个参数是rejected状态的回调函数。 当p的状态从pending变成了rejected,函数2会执行。
其中第二个参数是可选的,如果只写一个参数的话就是如下:
promise对象.then(函数1)
2.执行逻辑
以如下代码为例
let p = new Promise((resolve,reject)=>{
// resolve(val1);
reject(val2)
})
p.then(
okVal =>{
console.info("成功");
console.log(okValue);
},
errVal=>{
console.info("失败");
console.log(errValue);
}
)
它的两个参数都是函数,其执行逻辑是:
- 如果promise对象的状态是resolved,则then()会执行第一个函数,并传入当前的PromiseValue(即上面的val1);
- 如果promise对象的状态是rejected,则then()会执行第二个函数,并传入当前的PromiseValue(即上面的val2);
- 特别地,如果promise对象的状态是rejected,且此时then方法并没有设置第二个参数,就会向外抛出一个错误,错误的提示大约是Uncaught (in promise)。
如下是图示
3.then的返回值(难点)
then()方法的返回值也是一个promise对象,但是要注意的是它的返回值是一个新的promise对象,与调用then方法的并不是同一个对象。
看如下代码:
let p1 = new Promise(()=>{});
let p2 = p1.then(function f_ok(){}, function f_err(){});
// p2也是一个promise对象。
console.log(p1 === p2); // false
如上代码可以说明p1.then()的结果是一个与p1不同的promise对象。换句话说,then()会封装一个全新的promise对象p2。那既然 p2也是一个promise对象,那么,p2的状态(promiseStatus)和值(promiseValue)分别是什么?
p2的状态及promiseValue如何确定?
p2的状态及promiseValue按如下规则来确定
- 如果p1的状态是pending,则p2的状态也是pending。
- 如果p1的状态是resolved,then()会去执行f_ok,则p2的状态由f_ok的返回值决定。
-
- 如果f_ok返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_ok函数的return值。
- 如果f_ok返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。
- 如果f_ok这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。
- 如果p1的状态是rejected,then()会去执行f_err,则p2的状态由f_err的返回值决定。
-
- 如果f_err返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_err函数的return值。
- 如果f_err返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。
- 如果f_err这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。
四.catch的格式及用法
catch 是 then(null, reject)的别名
catch()的格式及用法
Promise.prototype.catch 是 Promise.prototype.then(null, reject)的别名,用于指定当promise对象的状态从pending变成rejected的回调函数 。
let p1 = new Promise((resolve,reject)=>{
reject('s')
});
p1.catch(function(err){
console.log(err);
})
// 与下面的代码等价
p1.then(null, function(err){
console.log(err);
})
单独使用catch没有什么意义,它一般与then一块使用。如下:
new Promise((resolve,reject)=>{
}).then(function(result){
// 如果promise对象的状态是resolved的,就会到这里来,并且result会接收promiseValue的值
}).catch(function(err){
// 如果promise对象的状态是rejected的,就会到这里来,并且err会接收promiseValue的值
})
// 上面的代码如何拆分来写的话,等价于:
let p1 = new Promise((resolve,reject){
});
let p2 = p1.then(function(result){
});
let p3 = p2.catch(function(err){
})
catch的返回值
catch的返回值仍是一个promise对象,确定它的值的方式与then(null,(errVal)=>{ })的方式一致。
五.Promise-链式调用
p.then()的返回值是一个新的promsie对象
编写代码进行讲解
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功1')
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功2')
}, 2000)
})
p.then(res => {
console.log(res);
return p2 // 如果return一个Promise对象,它的结果, 会被下个then接收
}).then(res => {
console.log(res);
})
六.Promise-解决回调地狱
// 前提: axios函数在原地返回的就是一个Promise对象
let pname = ''
axios.get('http://ajax-api.itheima.net/api/province').then(res => {
// 2. 获取某个省, 对应的城市列表
pname = res.data.data[5];
return axios.get(`http://ajax-api.itheima.net/api/city?pname=${pname}`)
}).then(res => {
// 3. 获取某个市, 对应的地区列表
let cname = res.data.data[0]
return axios.get(`http://ajax-api.itheima.net/api/area?pname=${pname}&cname=${cname}`)
}).then(res => {
console.log(res);
})
七.Promise的静态方法
Promise.all()方法
// 静态(类)方法: 直接用Promise类来调用
// 1. Promise.all()
// 作用: 合并多个Promise对象, 等待所有成功后, 返回结果
// 语法: Promise.all([promise对象1, promise对象2, ...]).then()
// 特点: 返回最终结果是个数组, 值是按顺序对应小Promise对象的成功结果
// 注意: 如果有1个Promise失败, 则整个Promise对象则失败
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功1')
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功2')
}, 2000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功3')
}, 2000)
})
Promise.all([p1, p2, p3]).then(res => {
console.log(res);
})
Promise.allSettled
// Promise.allSettled的语法和Promise.all一致 但返回值有区别 Promise.allSettled([p1, p2, p3])会返回状态和值而Promise.all值返回值且失败时只返回失败的值
// 作用: 合并多个Promise对象, 等待所有成功后, 返回结果
// 语法: Promise.all([promise对象1, promise对象2, ...]).then()
// 特点: 返回最终结果是个数组, 值是按顺序对应小Promise对象的成功结果
// 注意: 如果有1个Promise失败, 则整个Promise对象则失败
// const p = Promise.all([p1, p2, p3])
const p = Promise.allSettled([p1, p2, p3])
console.log(p);
Promise.race()方法
// 静态(类)方法: 直接用Promise类来调用
// 1. Promise.race() - 赛跑机制
// 作用: 发起并行多个Promise对象, 等待只要任何一个有结果(成功|失败), 返回结果执行then
// 语法: Promise.race([promise对象1, promise对象2, ...]).then()
// 特点: 返回第一个有结果的promise对象的结果
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功1')
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功2')
}, 2000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功3')
}, 2000)
})
Promise.race([p1, p2, p3]).then(res => {
console.log(res);
})
Promise的静态方法resolve和reject
Promise.resolve
创建一个状态为resolved的promise对象,并指定其值。或者理解为:把值转成Promise对象,并设置状态和值。 格式如下:
const p = Promise.resolve(值)
Promise.reject
格式如下:
const p = Promise.reject(值)