当前位置:网站首页>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日
边栏推荐
- xss-labs靶场挑战
- Batch大小不一定是2的n次幂!ML资深学者最新结论
- 使用KeyStore生成证书
- 什么是步进电机?40张图带你了解!
- C language game - minesweeper
- 【软件架构模式】MVVM模式和MVC模式区别
- What's up with VS "Cannot find or open PDB file"?How to solve
- Go-Excelize API source code reading (8) - GroupSheets(sheets []string), UngroupSheets()
- 广域铭岛入选2022年重庆市数字经济产业发展试点示范项目名单
- notes....
猜你喜欢
MySQL 必现之死锁
CTFshow,命令执行:web34、35、36
C#/VB.NET convert PPT or PPTX to image
redis
Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (2) Mini Program Functions
Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (3) Background Functions
周鸿祎称微软抄袭 360 安全模式后发文否认;英特尔CEO基辛格回应市值被AMD超越:股价下跌是咎由自取|极客头条
CTO strongly banning the use of the Calendar, that in what?
WPF 截图控件之绘制箭头(五)「仿微信」
C#/VB.NET 将PPT或PPTX转换为图像
随机推荐
Go-Excelize API source code reading (8) - GroupSheets(sheets []string), UngroupSheets()
C语言程序设计50例(三)(经典收藏)
Mysql index related knowledge review one
可视化——Superset安装与部署
基于ModelArts的物体检测YOLOv3实践【玩转华为云】
50.【动态二维数组的运用】
CTFshow,命令执行:web32
解决new Thread().Start导致高并发CPU 100%的问题
编码解码(btoa、encodeURIComponent、encodeURI、escape)
阿里腾讯面试一二
Generate certificates using KeyStore
CTFshow,命令执行:web34、35、36
Cross-domain network resource file download
如何在IntellJ IDEA中批量修改文件换行符
Introduction to STM32 development Introduce IIC bus, read and write AT24C02 (EEPROM) (using analog timing)
July 31, 2022 -- Take your first steps with C# -- Use arrays and foreach statements in C# to store and iterate through sequences of data
SQL Server database schema and objects related knowledge notes
xss漏洞学习
PDMan-国产免费通用数据库建模工具(极简,漂亮)
C#/VB.NET 将PPT或PPTX转换为图像