书接上回
8.指定多个回调
这个是什么意思呢? 在原生Promise
中有这样一个特性.
let p = new Promise((resolve,reject)=>{
//异步调用
setTimeout(()=>{
resolve("OK");
},100)
});
p.then(value=>{
console.log(111)
},reason => {
console.log(reason)
})
p.then(value=>{
console.log(222)
},reason => {
console.log(reason)
})
//输出
//111
//222
Promise
指定多个回调后,状态改变之后,这些回调全部都会执行.我们就是要实现的这个功能.
在之前保存回调函数的时候,我们使用的是对象来保存的.而如果想要保存多个回调函数,就需要用到数组来保存.
修改后的代码如下:
function PromiseA(executor){
//添加属性
this.PromiseState = "pending";
this.PromiseResult = null;
//-------------- 修改的代码-----------------
this.callbacks = [];
//-------------- 修改的代码-----------------
//预先保存实例对象的this值
const self = this;
//resolve函数
function resolve(data){
//判断状态
if(self.PromiseState !== "pending"){
return ;
}
//1.修改对象的状态(PromiseState)
self.PromiseState = "fulfilled";
//2.设置对象的结果值(PromiseResult)
self.PromiseResult = data;
//-------------- 修改的代码-----------------
//调用成功的回调函数
self.callback.forEach(item=>{
item.onResolved(data);
})
//-------------- 修改的代码-----------------
}
function reject(data){
//判断状态
if(self.PromiseState !== "pending"){
return ;
}
//1.修改对象的状态(PromiseState)
self.PromiseState = "rejected";
//2.设置对象的结果值(PromiseResult)
self.PromiseResult = data;
//-------------- 修改的代码-----------------
//调用失败的回调函数
self.callback.forEach(item=>{
item.onRejected(data);
})
//-------------- 修改的代码-----------------
}
//处理 throw 抛出的错误
try{
//同步调用一下
executor(resolve,reject);
}catch (e){
//通过调用reject函数,它的内部可以修改状态的和赋值
//所以我们这里可以把错误直接传进去就可以了.
reject(e);
}
}
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//调用 成功 回调函数
if(this.PromiseState === "fulfilled"){
onResolved(this.PromiseResult);
}
//调用失败的回调函数
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending状态的处理
if(this.PromiseState === "pending"){
//-------------- 修改的代码-----------------
//保存回调函数
this.callbacks.push({
onResolved,
onRejected
});
//-------------- 修改的代码-----------------
}
}
然后在callbacks
调用的地方改为数组遍历的方式进行调用.
9.同步任务 then 返回结果的实现
let p = new Promise((resolve,reject)=>{
resolve("OK");
});
const result = p.then(value=>{
console.log(111)
},reason => {
console.log(reason)
})
console.log(result)
看官方的实现, result
的结果由p.then
的回调函数的执行结果决定.
如果构造函数中成功,就执行第一个函数,那就由第一个函数决定.否则就由第二个决定.
它会返回一个Promise对象,而Promise对象的结果又取决于 回调函数的返回值.
其中又分为三种情况:
- 返回非
Promise
对象的,比如123,ok
,不返回就是undefined
,那么它默认会执行返回成功的Promise
对象, - 返回
Promise
对象的,则由这个对象决定状态,如果这个这个对象是成功的,那么外部result
就是成功,如果失败的,那么外部就是失败的. - 如果抛出错误,那么外部对象就是失败的.
我们一步一步的来解决上诉的问题:
9.1 既然返回结果是一个Promise,安排
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
return new PromiseA((resolve,reject)=>{
//调用 成功 回调函数
if(this.PromiseState === "fulfilled"){
onResolved(this.PromiseResult);
}
//调用失败的回调函数
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending状态的处理
if(this.PromiseState === "pending"){
//保存回调函数
this.callbacks.push({
onResolved,
onRejected
});
}
})
}
我们通过new PromiseA
来包裹一下then
方法中的处理函数. 这一步和官方的Promise
的使用很像,
let p = new Promise((resolve,reject)=>{
//异步调用
setTimeout(()=>{
resolve("OK");
},100)
});
它的里面通过调用resolve
和reject
来实现状态的改变.
所以我们这里也可以通过调用new PromiseA
时自带的resolve
和reject
函数来改变返回的PromiseA
的状态.
而返回的PromiseA
的状态又是取决于回调函数的结果.结果在哪里?
当然是在onResolved(this.PromiseResult)
里.
所以
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
return new PromiseA((resolve,reject)=>{
//调用 成功 回调函数
if(this.PromiseState === "fulfilled"){
//-------------- 修改的代码-----------------
let result = onResolved(this.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
//-------------- 修改的代码-----------------
}
//调用失败的回调函数
if(this.PromiseState === "rejected"){
//...
}
//添加pending状态的处理
if(this.PromiseState === "pending"){
//...
}
})
}
我们拿到 result
的结果.
let result = onResolved(this.PromiseResult);
它就是then
方法执行第一个回调函数的返回结果,来判断它是否为PromiseA
的对象.
如果不是,按照我们上面整理出的规则,就是成功的状态,所以通过调用外部对象的resolve
来进行改变.
如果判断对象是Promise
呢 ?
返回Promise
对象的,则由这个对象决定状态,如果这个这个对象是成功的,那么外部result
就是成功,如果失败的,那么外部就是失败的.
那么怎么拿到这个返回Promise
对象的状态呢?
我们知道当Promise
对象一旦状态发生改变,它就会回调它的then
方法中的回调.所以我们这里自己去调用它的then
方法.
PromiseA.prototype.then = function (onResolved,onRejected){
//这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
return new PromiseA((resolve,reject)=>{
//调用 成功 回调函数
if(this.PromiseState === "fulfilled"){
let result = onResolved(this.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//-------------- 修改的代码-----------------
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
//-------------- 修改的代码-----------------
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
}
//调用失败的回调函数
if(this.PromiseState === "rejected"){
//...
}
//添加pending状态的处理
if(this.PromiseState === "pending"){
//...
}
})
}
我们通过在它的内部调用 resolve
来修改外部 我们创建的那个Promise
对象的状态.
最后还有一个的状态就是错误的处理,我们只需要try catch
一下就可以了
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
return new PromiseA((resolve,reject)=>{
//调用 成功 回调函数
if(this.PromiseState === "fulfilled"){
//-------------- 修改的代码-----------------
try{
//-------------- 修改的代码-----------------
let result = onResolved(this.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
//-------------- 修改的代码-----------------
}catch (e){
reject(e);
}
//-------------- 修改的代码-----------------
}
//调用失败的回调函数
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending状态的处理
if(this.PromiseState === "pending"){
//保存回调函数
this.callbacks.push({
onResolved,
onRejected
});
}
})
}
测试用例:
let p = new PromiseA((resolve,reject)=>{
resolve("OK");
});
const result = p.then(value=>{
return new PromiseA((resolve,reject)=>{
resolve("111") //输出一
//reject("error")//输出二
})
//return 111;//输出三
//throw "error" //输出四
},reason => {
console.log(reason)
})
console.log(result)
//输出一
PromiseA {
PromiseState: 'fulfilled',
PromiseResult: '111',
callbacks: []
}
//输出二
PromiseA {
PromiseState: 'rejected',
PromiseResult: 'error',
callbacks: []
}
//输出三
PromiseA {
PromiseState: 'fulfilled',
PromiseResult: 111,
callbacks: []
}
//输出四
PromiseA {
PromiseState: 'rejected',
PromiseResult: 'error',
callbacks: []
}
可以看到结果发生了改变
10 异步任务 then 返回结果
这一次我们解决的是
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("OK");
})
});
const result = p.then(value=>{
console.log(111)
},reason => {
console.log(reason)
})
console.log(result)
通过异步调用resolve
来执行修改内部的状态.还记得之前我们处理异步的时候是在哪里吗?
通过判断状态PromiseState
为pending
,把回调函数onResolved
和onRejected
保存到实例对象的callbacks
上.
然后在未来改变的那一刻 调用 这些函数,来实现状态的改变.
而我们现在也同样需要在这里进行处理.它的区别其实和上面同步的不大,只不过一个是未来调用的.一个是当下调用的.
我们把pending
状态下的回调函数做一下处理:
//添加pending状态的处理
if(this.PromiseState === "pending"){
//保存回调函数
this.callbacks.push({
onResolved:function (){
//执行成功的回调函数
let result = onResolved(this.PromiseResult);
if(result instanceof PromiseA){
}else{
resolve(result);
}
},
onRejected:function (){
}
});
}
当onResolved
这个函数在未来被调用的时候,this.PromiseResult
这个值就无法拿到了,因为这里不再是对象调用,发生了隐式绑定的情况.
而是脱离了当前执行上下文环境,所以我们这里需要利用词法作用域的特性,设置一个self
来处理
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
return new PromiseA((resolve,reject)=>{
//调用 成功 回调函数
if(self.PromiseState === "fulfilled"){
//...
}
//调用失败的回调函数
if(self.PromiseState === "rejected"){
//...
}
//添加pending状态的处理
if(self.PromiseState === "pending"){
//保存回调函数
self.callbacks.push({
onResolved:function (){
try{
let result = onResolved(self.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
}catch (e){
reject(e);
}
},
onRejected:function (){
try{
let result = onRejected(self.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
}catch (e){
reject(e);
}
}
});
}
})
}
异步任务的执行回调处理其实和同步的一样,区别仅仅只是未来执行的时机而已.
所以在未来改变状态的时候,我们的外部Promise
对象的状态还是取决于它then
方法回调函数的返回值.
- 如果是非
Promise
对象,则状态为成功, - 如果是
Promise
对象,则状态取决于这个对象的状态,所以我们需要调用它的then
方法,给它添加上回调函数,在回调函数中去修改外部对象的状态 - 就是处理一下错误
11 优化一下then 函数
发现在同步任务中 还有一个rejected
状态没有处理,而它的逻辑又和fulfilled
状态的一样,区别只是调用不同的方法而已:
//调用失败的回调函数
if(self.PromiseState === "rejected"){
try{
let result = onRejected(self.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
}catch (e){
reject(e);
}
}
是不是发现上面的这段代码重复了太多次,我们优化一下,把这个方法统一成一个函数:
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
return new PromiseA((resolve,reject)=>{
//抽象成一个函数
function callback(type){
try{
let result = type(self.PromiseResult);
//判断 result 是 Promise 对象
if(result instanceof PromiseA){
//如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
//Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
result.then(v=>{
//在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 数据 则成功,通过调用resolve来修改
resolve(result);
}
}catch (e){
reject(e);
}
}
//调用 成功 回调函数
if(self.PromiseState === "fulfilled"){
callback(onResolved);
}
//调用失败的回调函数
if(self.PromiseState === "rejected"){
callback(onRejected);
}
//添加pending状态的处理
if(self.PromiseState === "pending"){
//保存回调函数
self.callbacks.push({
onResolved:function (){
callback(onResolved);
},
onRejected:function (){
callback(onRejected);
}
});
}
})
}