当前位置:网站首页>Promise学习(三)Promise的几个关键性问题 -- 状态改变、执行顺序与机制、多任务串联、异常穿透、中断promise链
Promise学习(三)Promise的几个关键性问题 -- 状态改变、执行顺序与机制、多任务串联、异常穿透、中断promise链
2022-08-01 10:21:00 【對不起该用户已成仙】
目录
前言
问题一、Promise 状态的改变?
1. resolve 转为成功状态
resolve(value): 如果当前是pending就会变为fulfilled (resolved)
let p = new Promise((resolve, reject) => {
resolve('ok'); // pending => fulfilled (resolved)
});
console.log(p);
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})

2. reject 转为成功状态
reject(reason): 如果当前状态是pending就会变为rejected
let p = new Promise((resolve, reject) => {
reject("err"); // pending => rejected
});
console.log(p);
p.catch(reason => {
console.log(reason);
})

3. 抛出异常转为失败状态
抛出异常: 如果当前是pending就会变为rejected
let p = new Promise((resolve, reject) => {
throw '出错了';
});
console.log(p);
p.catch(reason => {
console.log(reason);
})

注:对于上面的失败状态可以执行
catch 方法来处理失败的回调
问题二、一个 promise 指定多个成功/失败回调函数, 都会调用吗?
当 promise 改变为对应状态时都会调用,改变状态后,多个回调函数都会调用,并不会自动停止。简而言之,就是只要 promise 改变了状态,其绑定的所有回调函数都会调用执行。
let p = new Promise((resolve, reject) => {
// resolve('ok');
reject('err');
});
console.log(p);
// 指定回调-1
p.then(value => {
console.log('我是第一个回调:' + value);
}).catch(reason => {
console.log('我是第一个回调:' + reason);
});
// 指定回调-2
p.then(value => {
console.log('我是第二个回调:' + value);
}).catch(reason => {
console.log('我是第二个回调:' + reason);
});

可以看到失败状态下,两个失败回调都被catch方法处理好返回了,同理,成功时会调用then方法一样返回对应的回调结果。
问题三、改变 promise 状态和指定回调函数谁先谁后?
(1) 都有可能
正常情况下是先改状态再指定回调,但也可以先指定回调再改变状态
- 先指定回调再改变状态(
异步):先指定回调 => 再改变状态 => 改变状态后才进入异步队列执行回调函数 - 先改状态再指定回调(
同步):改变状态 =>指定回调并马上执行回调
(2) 如何先改状态再指定回调?
注意: 指定并不是执行
- ① 在执行器中直接调用 resolve()/reject() --> 同步操作
- ② 延迟更长时间才调用 then() -->在
.then()这个方法外再包一层例如延时器这种方法,异步操作
(3) 什么时候才能得到数据?
- 如果
先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据 - 如果
先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据 - 也就是说只有当状态改变后才能得到数据
下面我们例出一个 先指定回调后改变状态 的小案例:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('okk');
}, 1000);
});
const dp = p.then(value => {
console.log('最终的回调结果为:' + value);
},reason=>{
console.log(reason);
});
console.log(dp);


可以看到我们将p的回调赋给了dp,并且此案例延时了改变状态,所以它是先指定回调,后改变状态,但最终回调的结果还是为状态改变后的输出,由此可以得出结论:
只有当状态改变后才能得到数据
问题四、promise.then()返回的新 promise 的结果状态由什么决定?
答: 由 then() 指定的回调函数执行的结果决定
(1)如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
(2)如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
(3)如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
let p = new Promise((resolve, reject) => {
resolve('ok'); // 成功
});
// 执行then方法
let result = p.then(value => {
// console.log(value);
// 1. 抛出错误
// throw '出错了!'; // 失败 reject
// 2. 返回结果是非 Promise 类型的对象
// return 111; // 成功 fulfilled 结果为返回值
// 3. 返回结果是 Promise 对象
return new Promise((resolve, reject) => {
reject('error了')
})
}, reason => {
console.warn(reason);
});
console.log(result);

有三种情况,由上面的案例可知(第三种情况,前面两种情况在代码注释中可以看到,这里就不一一例举了),我们先把 promise 改变状态为
成功,然后往then方法里面传入失败状态的 promise 对象,最后的结果是根据then中的对象的状态来决定的。
问题五、promise 如何串连多个操作任务?
- promise 的
then()返回一个新的 promise, 可以看成then()的链式调用 - 通过
then 的链式调用串连多个同步/异步任务,这样就能用then()将多个同步或异步操作串联成一个同步队列
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve('success');
});
}).then(value => {
console.log(value);
}).then(value => {
console.log(value);
});
由上面可以得到,只有当
p的状态变为成功'ok'时,第一个then的成功回调才会执行,然后回调函数中的结果'success',当then的第一个回调promise 对象成功时,会继续执行下一个回调,因为第一个then的回调返回了一个promise 成功的对象,所以他的返回值会传入到第二个then的回调里面,所以第二个then的回调 中会输出'success',但第二个then的回调没有返回值,所以第三个then回调输出undefined。

问题六、promise 异常穿透
- 当使用
promise的then 链式调用时, 可以在最后指定失败的回调 - 前面任何操作出了异常, 都会传到最后失败的回调 catch() 中处理
可以在每个then()的第二个回调函数(reason)中进行err处理,也可以利用
异常穿透特性,到最后用catch去承接统一处理,两者一起用时,前者(reason)会生效(因为reason已经将其处理,就不会再往下穿透),走不到后面的catch
这里补充一下之前的知识点,then方法有两个回调函数形式的参数,前者(
value)代表成功的回调,后者(reason)代表失败的回调。
then 的第二个回调 reason 处理 err 如下:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
// reject('err')
}, 1000);
});
p.then(value => {
console.log(111);
}).then(value => {
console.log(222);
}).then(value => {
throw '出错啦!'
return value; // 将失败的值传入下一个then中
}).then (value => {
console.log(value);
}, reason => {
console.warn(reason); // 失败时回调
});
异常穿透 处理 err 方法如下:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
});
p.then(value => {
console.log(111);
}).then(value => {
console.log(222);
}).then(value => {
// console.log(333);
throw '出错啦!'
}).catch (reason => {
console.warn(reason);
});
最后都会得到以下输出

问题七、中断 promise 链
应用场景:有上面的问题二可知,当promise状态改变时,他的所有链式调用都会生效,那如果我们有这个一个实际需求:我们有3个 then(),假如其中有条件判断,不符合第一个 then() 条件时,要直接中断链式调用,不再运行调用下面的 then() ,解决方法如下。
- 当使用 promise 的
then链式调用时, 在中间中断, 不再调用后面的回调函数 - 办法: 在回调函数中返回一个
pendding状态的promise 对象
return new Promise(() => {});// 返回一个pending状态的Promise对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(111);
//有且只有一个方式
// 返回一个pending状态的Promise对象
return new Promise(() => {
});
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});

Authors: min
时间: 2022年7月26日
边栏推荐
- 开天aPaaS之移动手机号码空号检测【开天aPaaS大作战】
- Introduction and application of pointers
- 如何从完美的智能合约中窃取 1 亿美元
- 基于ModelArts的物体检测YOLOv3实践【玩转华为云】
- 企业微信群:机器人定时提醒功能数据库配置化
- 复现assert和eval成功连接或失败连接蚁剑的原因
- Introduction and application of heap memory (including examples)
- 小程序毕设作品之微信美食菜谱小程序毕业设计成品(4)开题报告
- 深度学习 | MATLAB实现一维卷积神经网络convolution1dLayer参数设定
- Shell: Conditional test action
猜你喜欢
![[Software Architecture Mode] The difference between MVVM mode and MVC mode](/img/37/8470ff9267752d4ca26a6b54ec0b50.png)
[Software Architecture Mode] The difference between MVVM mode and MVC mode

CTFshow,命令执行:web32
retired paddling

Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (3) Background Functions

50.【动态二维数组的运用】

Opencv creates a window - cv.namedWindow()

CTFshow,命令执行:web34、35、36

如何从完美的智能合约中窃取 1 亿美元

Google Earth Engine APP——15行代码搞定一个inspector高程监测APP

Android Security and Protection Policy
随机推荐
What is a stepper motor?40 pictures to show you!
RK3399平台开发系列讲解(内核入门篇)1.52、printk函数分析 - 其函数调用时候会关闭中断
4种常见的鉴权方式及说明
Basic configuration commands of cisco switches (what is the save command of Huawei switches)
浏览器快捷键大全
Endorsed in 2022 years inventory | product base, science and technology, guangzhou automobile group striding forward
MFC实现交通图导航系统
线上问题排查常用命令,总结太全了,建议收藏!!
招聘随想2022
数仓分层简介(实时数仓架构)
Android Security and Protection Policy
CTFshow,命令执行:web31
PowerPC技术与市场杂谈
IntellJ IDEA如何显示换行符(line endings)
50.【Application of dynamic two-dimensional array】
正则表达式
The meaning and trigger conditions of gc
Dataset之mpg:mpg数据集的简介、下载、使用方法之详细攻略
微信公众号授权登录后报redirect_uri参数错误的问题
STM32入门开发 介绍IIC总线、读写AT24C02(EEPROM)(采用模拟时序)