手写Promise封装继续行进----实现then方法的结构功能!
按照步骤进行,逻辑思路很简单易实现!
前文链接导航:
功能1:搭建Promise结构,实现关键resolve、reject功能
功能2:实现throw抛出异常以及Promise对象状态单次更改功能
本文在前两篇的实现基础上继续封装Promise其他功能
1:then()方法执行回调的实现
- 首先:实例化对象中调用then方法
<script src="./Promise.js"></script>
<body>
<script>
let p = new Promise((resolve, reject) => {
// reject('error');
resolve('OK');
// 抛出异常
// throw "error"
})
console.log(p)
// 实例调用then方法
p.then(value => {
console.log(value);//成功用log输出
}, reason => {
console.warn(reason);//失败用warn输出
})
</script>
- 注释掉script标签引用,查看内置Promise的表现,明确自定义封装预期结果,结果如下:
//注释掉下列代码,查看内置表现
<script src="./Promise.js"></script>
- 恢复script标签引入,因为我们没有进行相应的封装,没有调用then方法,所以还不能实现上述功能,由于同步执行,所以需要在Promise.then()方法中调用回调函数,逻辑结构如下:
代码结构为:
// 添加then方法
Promise.prototype.then=function(onResolved,onRejectd){
// 调用回调函数,这里不能直接调用,因为promise的状态是不一定的
if(){
// 成功调用onResolved
onResolved();
}
if(){
// 失败调用onRejected
onRejectd();
}
}
分析判断条件:
我们知道成功和失败的不同状态会回调不同的函数,那么成功和失败的判断条件是什么呢?
----应该是上述Promise实例对象中声明的PromiseState这个属性(不懂请导航到前两篇文章...
具体代码如下:
// 添加then方法
Promise.prototype.then=function(onResolved,onRejectd){
// 调用回调函数,这里不能直接调用,因为promise的状态是不一定的
if(this.PromiseState === 'fulfilled'){
// 成功调用onResolved
onResolved();
}
if(this.PromiseState === 'rejected'){
// 失败调用onRejected
onRejectd();
}
}
代码中的this指向问题解释:
1:then方法是由p这个Promise实例调用的,所以在这个对象中,this就是指向实例对象p的
2:所以this.PromiseState获取的就是p这个实例的PromiseState属性
4:继续向下发现问题,逻辑关系展示:
上图问题描述:
1: 实例p.then()中的回调函数声明时是有形参的(value或者reason)
2: 这个函数在调用时是传给了.then()方法中的onResolved实参
3:但是按照上述代码,调用时并没有给传递相应参数
4:这个参数是保存了上述状态更改的具体值,也就是之前声明的PromiseResult这个属性
5:于是继续完善代码如下:
// 添加then方法
Promise.prototype.then=function(onResolved,onRejectd){
// 调用回调函数,这里不能直接调用,因为promise的状态是不一定的
if(this.PromiseState === 'fulfilled'){
// 成功调用onResolved
onResolved(this.PromiseResult);
}
if(this.PromiseState === 'rejected'){
// 失败调用onRejected
onRejectd(this.PromiseReslut);
}
}
逻辑分析:
代码执行结果:
当然可以验证reject 以及 throw 改变promise状态,同时调用.then方法,这里暂不展示,大家可以自行验证。
至此,我们队then方法中回调的执行有了一个完整的实现!但是…
注意:
1:以上三节代码都是执行器中的函数为同步执行,即通过resolve(' OK '),直接改变Promise对象的状态,而不是异步改变的。
2:在接下来的封装中,考虑执行器中使用异步方式 :
let p = new Promise((resolve, reject) => {
// 执行器中异步执行改变状态
setTimeout(()=>{
resolve('OK');
},1000)
// 执行器中同步执行改变状态
// reject('error');
// resolve('OK');
// 抛出异常
// throw "error"
})
3:使用setTimeout()也只是用定时器做一个模拟,方便实现
而在实际中,可能是一个文件的IO,数据库的IO,也可能是一个网络请求的IO,
总之是异步的,并不是立刻改变对象状态的
4:对于这种异步的,要求也是能够成功执行回调的,显然我们目前封装的代码还不可以实现。
总结:这里放上截止目前手写Promise的完整代码,包含以往三部分的全部功能,如下:
全部功能:
1:搭建自定义Promise结构,实现关键resolve、reject功能。
2:实现throw抛出异常改变对象状态
3:确保Promise对象状态只能更改一次
4:实现关键then方法的调用功能
index.html中全部代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise封装</title>
</head>
<script src="./Promise.js"></script>
<body>
<script>
let p = new Promise((resolve, reject) => {
// 执行器中异步执行改变状态
setTimeout(()=>{
resolve('OK');
},1000)
// 执行器中同步执行改变状态
// reject('error');
// resolve('OK');
// 抛出异常
// throw "error"
})
// console.log(p)
// 实例调用then方法
p.then(value => {
console.log(value);//成功用log输出
}, reason => {
console.warn(reason);//失败用warn输出
})
</script>
</body>
</html>
Promise.js中全部代码:
// 声明构造函数
function Promise(executor){
// 添加属性,以便下面修改
this.PromiseState="pendding";
this.PromiseResult=null;
// 保存实例对象的 this 的值
const self=this;
// resolve函数
function resolve(data){
// 判断状态
if(self.PromiseState !== 'pendding') return;
// 1.修改对象的状态
self.PromiseState="fulfilled";//和resolved一样的含义,都表示成功
// 2.设置对象的结果值
self.PromiseResult=data;
}
// reject函数
function reject(data){
// 判断状态
if(self.PromiseState !== 'pendding') return;
// 1.修改对象的状态
self.PromiseState="rejected";
// 2.设置对象的结果值
self.PromiseResult=data;
}
try{
// 同步调用 -- 执行器函数
executor(resolve,reject);
}catch(err){
// 修改 promise 对象的状态为失败
reject(err);
}
}
// 添加then方法
Promise.prototype.then=function(onResolved,onRejectd){
// 调用回调函数,这里不能直接调用,因为promise的状态是不一定的
if(this.PromiseState === 'fulfilled'){
// 成功调用onResolved
onResolved(this.PromiseResult);
}
if(this.PromiseState === 'rejected'){
// 失败调用onRejected
onRejectd(this.PromiseReslut);
}
}
对应的代码在每一个小节中都有详细的介绍,务必注意搞清逻辑关系,实现起来就会很灵活轻松! 后续异步执行功能继续更新封装,敬请期待,感谢观看!