一、核心
简要概括:Promise的主要作用是作为一个存储 状态 和 结果 的容器。
1、Promise对象的内部属性变量
本文所说的内部属性变量的意思就是:JS代码中不能通过任何方法获取或者赋值的属性变量。
这种变量在Promise对象中有两个:
1.1、PromiseStatus
用于存储执行状态的变量,其固定只有三种值,代表三种不同的状态。本文称为PromiseStatus
变量(Google浏览器控制台上显示的属性变量名)。
pending
代表进行中的状态,是PromiseStatus
变量的初始值,变量值为pending
时才能进行修改值resolved
代表已成功的状态,只有当PromiseStatus
变量为pending
的情况下,才能将值变为resolved
。变量值为resolved
后,不可以在进行修改,代表状态凝固。有的时候也会用fulfilled
表示。rejected
代表已失败的状态,只有当PromiseStatus
变量为pending
的情况下,才能将值变为rejected
。变量值为rejected
后,不可以在进行修改,代表状态凝固。
1.2、PromiseValue
用于存储状态改变后的结果的变量,其值可以使用大部分数据类型作为结果数据值(目前Promise实例对象不可以作为该变量的值)。本文称为PromiseValue
变量(Google浏览器控制台上显示的属性变量名)。变量的初始值为undefined
,且只有一次修改的机会,就是在PromiseStatus
变量的值从pending
变为其他状态的时候,同步修改PromiseValue
变量的值,这一次的修改后,Promise对象的PromiseValue
变量的值就不会在修改了。
注意
:这两个变量只能在浏览器的控制台上显示一下,代码中实际上是不能直接获取操作的,只有通过实例对象的原型对象上的某些方法的使用,间接知道这两个变量的存在
2、Promise类构造函数中,两个特殊函数
2.1、RESOLVE函数
将实例对象的PromiseStatus
变量的值修改为resolved
,同时将调用函数时传入的参数一数据
赋值给实例对象的PromiseValue
变量。这个函数在本文称为RESOLVE函数
2.2、REJECT函数
将实例对象的PromiseStatus
变量的值修改为rejected
,同时将调用函数时传入的参数一数据
赋值给实例对象的PromiseValue
变量。这个函数在本文称为REJECT函数
2.3、调用RESOLVE或REJECT
这两个特殊函数目前只在一个地方可以让开发人员获取到并被调用:
-
在使用Promise构造函数创建实例对象时,Promise构造函数必须有一个函数对象作为参数一,而在Promise构造函数内部会使用
RESOLVE
函数作为参数一,REJECT
函数作为参数二,去调用 Promise构造函数调用时传入的参数一函数,如此在这个构造函数的参数一函数的函数体中,我们就可以获取并调用RESOLVE
函数和REJECT
函数// 使用Promise的构造函数时,必须有函数对象作为参数一 new Promise(); // Uncaught TypeError: Promise resolver undefined is not a function // Promise构造函数内部先新建了一个Promise实例对象,然后调用了构造函数的参数一函数 // 在参数一函数中并没有调用RESOLVE函数或者REJECT函数, // 所以新建实例对象的PromiseStatus变量和PromiseValue变量的值依然为初始值 new Promise(function(RESOLVE,REJECT){}); // Promise {<pending>: undefined} // 在Promise构造函数的参数一函数中调用了RESOLVE函数, // 所以新建实例对象的PromiseStatus变量修改值为resolved,PromiseValue变量修改值为1 new Promise(function(RESOLVE,REJECT){ RESOLVE(1); }); // Promise {<resolved>: 1} // 在Promise构造函数的参数一函数中调用了REJECTE函数, // 所以新建实例对象的PromiseStatus变量修改值为rejected,PromiseValue变量修改值还值为undefined new Promise(function(RESOLVE,REJECT){ REJECT(); }); // Promise {<rejected>: undefined} // Promise构造函数的参数一函数的函数体中,RESOLVE函数被调用后, // 新建实例对象的PromiseStatus变量值此时已经修改为resolved, // 接着又调用了REJECT函数,REJECT函数内部发现新建实例对象的PromiseStatus变量值不再是pending后 // REJECT函数便不会在继续执行,REJECT函数调用失效 new Promise(function(RESOLVE,REJECT){ RESOLVE(26); REJECT(); }); // Promise{<resolved>: 26} // 同理如果先调用了REJECT函数,那么RESOLVE函数的调用就会失效 new Promise(function(RESOLVE,REJECT){ REJECT(62); RESOLVE(); }); // Promise{<rejected>: 62}
猜测:
RESOLVE
和REJECT
函数是绑定了Promise实例对象后的函数,所以这两个函数只能修改绑定的Promise对象。每个RESOLVE
和REJECT
函数都只属于唯一一个Promise对象的。// 伪代码演示Promise中如何生成和传递RESOLVE和REJECT两个函数 var resolve = function(){/** 用于修改Promise实例对象的内部变量的函数 **/}; var reject = function(){/** 用于修改Promise实例对象的内部变量的函数 **/}; function Promise(argMethod){ // 猜测在Promise构造函数内部将resolve和reject函数和this对象, // 通过bind方法绑定生成了RESOLVE和REJECT函数 argMethod(resolve.bind(this),reject.bind(this)); } // 将RESOLVE和REJECT两个函数脱离构造函数去使用 var resolve; var reject; var p = new Promise((RESOLVE,REJECT)=>{ // 此处的RESOLVE和REJECT只能修改p对象的内容 // RESOLVE,REJECT两个函数只属于p对象 resolve = RESOLVE; reject = REJECT; }); p; // Promise {<pending>: undefined} resolve(123); p; // Promise {<resolved>: 123}
-
猜测:
then
方法内部会创建一个新Promis对象,且会将属于这个对象的RESOLVE
或者REJECT
两个函数与then
方法的两个参数函数绑定在一起作为一个个微任务。当调用then
方法的实例对象的状态不在处于pending
时,会将对应状态的微任务加入微任务队列中进行执行,具体的代码逻辑可以参考底部对Promise类还原的代码中then
方法的部分
2.4、调用时传递的参数
RESOLVE
或REJECT
两个函数在调用时可以传递大部分的数据,其内部猜测
都是直接对新建实例对象的PromiseStatus
变量和PromiseValue
变量进行修改,将两个函数的参数直接赋值给PromiseValue
变量,然后根据调用的是哪个函数,将PromiseStatus
变量修改为对应的状态。
但是也有特例的情况,如果传递的参数是Promise实例对象的话,或者是一个包含then
方法的对象,RESOLVE
函数内部的逻辑就不再是直接修改PromiseStatus
变量和PromiseValue
变量了,具体逻辑可以参考底部对Promise类还原的代码中amendPromiseResolved
或者amendPromiseRejected
方法的部分(但是REJECT
函数,依然直接修改Promise
对象的内部变量)
2.5、细节
当我们调用了RESOLVE
或REJECT
函数后,并不代表Promise构造函数的参数函数已经执行完了,我们还可以继续执行其他代码,但是不推荐这样写
new Promise((RESOLVE,REJECT)=>{
console.log('调用RESOLVE');
RESOLVE(123);
console.log('调用RESOLVE后,并不代表终结');
})
// 控制输出打印: 调用RESOLVE 调用RESOLVE后,并不代表终结
RESOLVE
或REJECT
函数在被调用时的实质只是修改了PromiseStatus
变量和PromiseValue
变量,然后在判断下Promise实例对象中是否记录了微任务,如果有记录就把微任务添加进微任务队列。
其内部并没有涉及到终结函数的内容,所以在RESOLVE
或REJECT
函数调用后,依然可以继续执行接下来的代码,直到代码全部执行完毕。
但是最好在RESOLVE
或REJECT
函数被调用后,就不要在有代码执行了,用return
替代
new Promise((RESOLVE,REJECT)=>{
console.log('调用RESOLVE');
RESOLVE(123);
return;
})
3、Promise.prototype.then
then
方法是用来获取Promise对象的PromiseStatus
和PromiseValue
的途径。
PromiseStatus
变量的值是不可以直接获取的,只有通过then
方法的参数函数被调用时,才能间接知道PromiseStatus
变量目前是哪个值:
var p1 = new Promise((RESOLVE,REJECT)=>{
if((new Date().getTime()%2)===0){
RESOLVE('当前时间戳是偶数');
}else{
REJECT('当前时间戳是奇数');
}
});
p1.then(
(resolvedResult)=>{/** 当本函数被调用时说明p1对象的PromiseStatus变量的值是resolved **/},
(rejectedResult)=>{/** 当本函数被调用时说明p1对象的PromiseStatus变量的值是rejected **/}
);
PromiseValue
变量的值是可以通过then
方法的参数函数的回调获取到的。且then
方法的参数函数被调用时所用的参数与Promise对象上的PromiseValue
变量的值是同一个数据:
var evenNumber = {desc:'偶数'};
var oddNumber = {desc:'奇数'};
var p1 = new Promise((RESOLVE,REJECT)=>{
if((new Date().getTime()%2)===0){
RESOLVE(evenNumber);
}else{
REJECT(oddNumber);
}
});
p1.then(
(resolvedResult)=>{
// resolvedResult就是p1对象的状态为resolved时,PromiseValue变量的值
console.log(resolvedResult===evenNumber); // 控制台输出打印 true
return resolvedResult;
},
(rejectedResult)=>{
// rejectedResult就是p1对象的状态为rejected时,PromiseValue变量的值
console.log(rejectedResult===oddNumber); // 控制台输出打印 true
return rejectedResult;
}
);
then
方法会返回一个新建的Promise
对象,这个对象是在then
方法内部创建的,且内部变量的初始值分别是 pending
、undefined
,当这个新建Promise
对象经过微任务的操作后,其内部变量才会发生改变:
var p = new Promise((RESOLVE,REJECT)=>{
RESOLVE(321);
})
// then方法中因为此时 p 的状态不是 pending ,所以将一个改变p1内部变量的微任务加入到了微任务队列中
var p1 = p.then(
(resolveResult)=>{ return '已成功' },
(rejectResult)=>{ return '已失败' }
);
p1; // 此时宏任务没有结束 p 的内部变量的值分别是 pending 和 undefined
debugger; // 使用断点让宏任务停在这里
// 当宏任务结束后,微任务也执行完,此时p1的内部变量发生了改变
p1; // p1内部变量分别是 resolved 和 '已成功'
调用then
方法时会传递两个参数函数,当调用then
方法的对象的状态不在是pending
时,那对应状态的参数函数会被调用,且会拿参数函数返回的数据作为参考去修改then
方法返回Promise
对象的内部变量:
var p1 = new Promise((RESOLVE,REJECT)=>{
RESOLVE(123);
})
var p2 = new Promise((RESOLVE,REJECT)=>{
REJECT(321);
})
var p3 = p1.then((x)=>{
console.log(x); // 输出打印 123
// 如果p1的状态是resolved,那么then参数一函数会被调用。
// 此处参数一函数的返回值是 undefined
// 所以 p3 最终修改内部变量后,其值分别是:
// resolved(因为在调用参数一函数时,函数没有抛出异常,所以PromiseStatus直接修改为resolved)
// undefined(因为在调用参数一函数时,函数没有抛出异常,所以PromiseValue以参数一函数的返回值作为其值)
},null); // 内部变量的值分别是 pending 和 undefined
var p4 = p1.then((x)=>{
console.log(x); // 输出打印 123
// 如果p1的状态是resolved,那么then参数一函数会被调用。
// 此处参数一函数的返回值是 hehehe,
// 所以 p4 最终修改内部变量后,其值分别是:
// resolved(因为在调用参数一函数时,函数没有抛出异常,所以PromiseStatus直接修改为resolved)
// hehehe(因为在调用参数一函数时,函数没有抛出异常,所以PromiseValue以参数一函数的返回值作为其值)
return 'hehehe'
},null); // 内部变量的值分别是 pending 和 undefined
var p5 = p2.then(null,(x)=>{
console.log(x); // 输出打印 321
// 如果p2的状态是rejected,那么then参数二函数会被调用。
// 此处参数二函数的返回值是 undefined
// 所以 p5 最终修改内部变量后,其值分别是:
// resolved(因为在调用参数二函数时,函数没有抛出异常,所以PromiseStatus直接修改为resolved)
// undefined(因为在调用参数二函数时,函数没有抛出异常,所以PromiseValue以参数二函数的返回值作为其值)
}); // 内部变量的值分别是 pending 和 undefined
var p6 = p2.then(null,(x)=->{
console.log(x); // 输出打印 321
// 如果p2的状态是rejected,那么then参数二函数会被调用。
// 此处参数二函数的返回值是 zezeze
// 所以 p6 最终修改内部变量后,其值分别是:
// resolved(因为在调用参数二函数时,函数没有抛出异常,所以PromiseStatus直接修改为resolved)
// undefined(因为在调用参数二函数时,函数没有抛出异常,所以PromiseValue以参数二函数的返回值作为其值)
return 'zezeze'
}); // 内部变量的值分别是 pending 和 undefined
var p7 = p1.then((x)=>{
console.log(x); // 输出打印 123
// 不管是参数一还是参数二函数返回值是Promise对象的情况下
// 那p7内部变量的修改都不在受p1以及then方法的参数函数影响了,
// p7内部变量的修改受到此处return返回的Promise对象的影响。
// 如果此处return返回的Promise对象的状态是resolved,那p7的状态就直接修改为resolved
// 如果此处return返回的Promise对象的状态是rejected,那p7的状态就直接修改为rejected
// 而p7的PromiseValue变量的值则直接使用return返回的Promise对象的值
return new Promise((RESOLVE,REJECT)=>{
REJECT('ERROR');
});
},null); // 内部变量的值分别是 pending 和 undefined
var p8 = p2.then(null,(x)=->{
console.log(x); // 输出打印 321
// 不管是参数一还是参数二函数返回值是Promise对象的情况下
// 那p8内部变量的修改都不在受p2以及then方法的参数函数影响了,
// p8内部变量的修改受到此处return返回的Promise对象的影响。
// 如果此处return返回的Promise对象的状态是resolved,那p8的状态就直接修改为resolved
// 如果此处return返回的Promise对象的状态是rejected,那p8的状态就直接修改为rejected
// 而p8的PromiseValue变量的值则直接使用return返回的Promise对象的值
return new Promise((RESOLVE,REJECT)=>{
RESOLVE('SUCCESS');
});
}); // 内部变量的值分别是 pending 和 undefined
debugger; // 使用断点让宏任务停在这里
// 当宏任务结束后,微任务也执行完
p3; // 内部变量的值分别是 resolved 和 undefined
p4; // 内部变量的值分别是 resolved 和 hehehe
// 即使p2的状态是rejected,但是通过p2调用then方法返回的新建实例对象状态也只会是resolved(如果不抛出错误的话)
p5; // 内部变量的值分别是 resolved 和 undefined
p6; // 内部变量的值分别是 resolved 和 zezeze
p7; // 内部变量的值分别是 rejected 和 ERROR
p8; // 内部变量的值分别是 resolved 和 SUCCESS
参数函数之所以会被调用,则是因为在then
方法内部会以参数函数为要素形成新的微任务,在then
方法中并不会直接调用参数函数。当调用then
方法的对象的状态不在是pending
时,就会将这些微任务加入到微任务队列中,微任务执行后,参数函数也就间接调用了。
如果调用then
方法时,没有传递参数函数,then
方法内部就会以调用then
方法的对象为要素形成新的微任务。
这就会导致没有参数函数的时候,then
方法返回的新建Promise
对象的内部变量的修改由调用hen方法的对象来决定。
var p1 = new Promise((RESOLVE,REJECT)=>{
RESOLVE(123);
})
var p2 = new Promise((RESOLVE,REJECT)=>{
REJECT(321);
})
var p3 = p1.then(null,()=>{ return '已失败' }); // 内部变量的值分别是 pending 和 undefined
var p4 = p2.then(()=>{ return '已成功' },null); // 内部变量的值分别是 pending 和 undefined
// 产生p5的then方法和产生p3的then方法效果是一样的,都是想使用参数一函数形成的微任务,
// 但是参数一函数没有传递,所以then方法内部使用p1形成微任务,p3和p5内部变量的修改就由p1决定了
// p1的内部变量是多少,那p3和p5的内部变量就是多少
var p5 = p1.then(); // 内部变量的值分别是 pending 和 undefined
// 产生p6的then方法和产生p4的then方法效果是一样的,都是想使用参数二函数形成微任务,
// 但是参数二函数没有传递,所以then方法内部使用p2形成微任务,p4和p6内部变量的修改就由p2决定了
// p2的内部变量是多少,那p4和p6的内部变量就是多少
var p6 = p2.then(); // 内部变量的值分别是 pending 和 undefined
debugger; // 使用断点让宏任务停在这里
// 当宏任务结束后,微任务也执行完,此时p3,p4,p5,p6的内部变量发生了改变
p3; // p3内部变量分别是 resolved 和 123
p4; // p4内部变量分别是 rejected 和 321
p5; // p5内部变量分别是 resolved 和 123
p6; // p6内部变量分别是 rejected 和 321
3.1、then方法的本质
then
方法的内部是创建一个新的Promise实例对象,并将属于新建Promise对象的RESOLVE和REJECT函数
、调用then方法的Promise对象
、then方法传入的参数一函数和参数二函数
这三个要素绑定合成了一个个微任务,接着判断调用then
方法的Promis对象的状态处于哪个阶段,根据不同的状态,来决定对合成的微任务
进行什么操作。
then
方法内部的逻辑伪代码可以参考底部对Promise类还原的代码中then
方法的部分
4、Promise中抛出错误
正常情况下,在JS代码中抛出错误,如果不捕捉抛出的错误,那代码执行会停在错误抛出处,不在继续执行。
// 未捕获抛出的错误
console.log('代码执行中,准备抛出错误'); // 输出打印了
throw '抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
// 捕获抛出的错误
console.log('代码执行中,准备抛出错误'); // 输出打印了
try{
throw '抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
}catch(error){
console.log('打印抛出的错误的信息:' + error);
}
console.log('虽然错误抛出后的代码依然不会在被执行,但是try/catch之后的代码可以执行了'); // 输出打印了
但是在Promise
的构造函数
的参数函数以及then
方法的参数函数,如果抛出了错误,这个错误并不会影响到Promise外
的代码执行。猜测在Promise内部已经对这些抛出的错误进行了捕获。
4.1、构造函数的参数函数中抛出错误
如果在构造函数的参数函数调用时抛出了错误,那么参数函数中的函数体执行代码会停在错误抛出处,并且直接修改构造函数所创建的Promise
对象的PromiseStatus
变量值为rejected
,PromiseValue
变量的值为抛出的错误
。
猜测:构造函数的参数函数有可能是在try/catch
中被调用的,当构造函数的参数函数在被调用时,出现错误后,会对错误进行捕获,并直接拿捕获的错误
作为调用REJECT
函数的参数。
var p = new Promise(()=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
throw '抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p; // 内部变量的值分别是:rejected 和 抛出的错误
console.log('Promise外的代码执行依然正常'); // 输出打印了
var p1 = new Promise(()=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
// 如果在参数函数中手动捕获抛出的错误,那按照没有错误抛出的逻辑了
try{
throw '抛出一个错误,代码执行停止';
}catch(error){}
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p1; // 内部变量的值分别是:pending 和 undefined
// 抛出错误的时候会调用REJECT函数,但是在抛出错误之前就已经调用RESOLVE或者REJECT函数的话,
// 那因为抛出错误而调用的REJECT函数就会无效
var p2 = new Promise((RESOLVE,REJECT)=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
RESOLVE('已成功')
throw '抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p2; // 内部变量的值分别是:resolved 和 已成功
var p3 = new Promise((RESOLVE,REJECT)=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
REJECT('已失败');
throw '抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p3; // 内部变量的值分别是:reject 和 已失败
var p4 = new Promise((RESOLVE,REJECT)=>{
RESOLVE('OK');
// 注意:此处抛出异常的地方是在延时函数中,即使延时是0,但是此处setTimeout函数的作用是将延时函数记录下来,
// 等待下次宏任务执行延时函数。而延时函数执行的地方就不在是Promise构造函数的参数函数中了,
// 所以其抛出的错误不会被Promise所捕获。
setTimeout(
()=>{ throw new Error('test'); },
0);
});
p4.then((x)=>{ console.log(x); });
// 当 当前宏任务 执行完后,执行微任务,输出打印:ok
// 微任务执行完后,继续执行宏任务,延时函数被调用。
4.2、then方法的参数函数中抛出错误
如果在then
方法的参数函数调用时抛出了错误,那么参数函数中的函数体执行代码会停在错误抛出处,并且直接修改then
方法所创建的Promise
对象的PromiseStatus
变量值为rejected
,PromiseValue
变量的值为抛出的错误
。
猜测:then
方法的参数函数有可能是在try/catch
中被调用的,当then
方法的参数函数在被调用时,出现错误后,会对错误进行捕获,并直接拿捕获的错误
作为调用REJECT
函数的参数。
var p1 = new Promise((RESOLVE,REJECT)=>{RESOLVE('已成功');});
var p11 = p1.then((resolveResult)=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
throw 'p1的then的参数函数抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
},null);
p11; // 内部变量的值分别是 pending 和 undefined
var p2 = new Promise((RESOLVE,REJECT)=>{REJECT('已失败');});
var p22 = p2.then(null,(RejectResult)=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
throw 'p2的then的参数函数抛出一个错误,代码执行停止';
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p22; // 内部变量的值分别是 pending 和 undefined
var p23 = p2.then(null,(RejectResult)=>{
console.log('代码执行中,准备抛出错误'); // 输出打印了
// 如果在参数函数中手动捕获抛出的错误,那按照没有错误抛出的逻辑了
try{
throw 'p2的then的参数函数抛出一个错误,代码执行停止';
}catch(error){}
console.log('错误抛出后的代码不会在被执行'); // 没有执行
});
p23; // 内部变量的值分别是 pending 和 undefined
debugger; // 使用断点让宏任务停在这里
p11; // 内部变量的值分别是:rejected 和 p1的then的参数函数抛出一个错误,代码执行停止
p22; // 内部变量的值分别是:rejected 和 p2的then的参数函数抛出一个错误,代码执行停止
p23; // 内部变量的值分别是:resolved 和 undefined
二、Promise余下内容
1、Promise.prototype.catch
Promise
对象调用catch
方法等价于调用then
方法只传参数二,参数一恒定是null
。
var p = new Promise((RESOLVE,REJEC)=>{ REJEC('已失败'); });
p.catch((rejectResult)=>{console.log(rejectResult);});
// 上下两行代码效果等价
p.then(null,(rejectResult)=>{console.log(rejectResult);});
2、Promise.prototype.finally
Promise
对象调用finally
方法的效果用then
方法也可以实现。
var p = new Promise((RESOLVE,REJEC)=>{ REJEC('已失败'); });
var finalFun = function(){
console.log('finally的回调函数');
}
p.finally(()=>{ finalFun(); });
// 上下两种代码效果等价
p.then(
(resolvedResult)=>{
finalFun();
return resolvedResult;
},
(rejectResult)=>{
finalFun();
throw rejectResult;
}
);
3、Promise.resolve
resolve
方法是属于Promise类的静态方法,方法内效果等价于,用new
关键字创建了一个新的Promise
对象,并且在构造函数的参数函数中立即调用了RESOLVE
函数,RESOLVE
函数的参数是resolve
静态方法的参数,并以新建Promise
对象的作为方法的返回值。
Promis.resolve('HeHeHe');
// 上下两种代码效果等价
new Promise((RESOLVE,REJECT)=>{
RESOLVE('HeHeHe');
});
4、Promise.reject
reject
方法是属于Promise类的静态方法,方法内效果等价于,用new
关键字创建了一个新的Promise
对象,并且在构造函数的参数函数中立即调用了REJECT
函数,REJECT
函数的参数是reject
静态方法的参数,并以新建Promise
对象的作为方法的返回值。
Promis.reject('HeHeHe');
// 上下两种代码效果等价
new Promise((RESOLVE,REJECT)=>{
REJECT('HeHeHe');
});
5、Promise.all
all
方法的特性:
all
方法是属于Promise
类的静态方法,方法在调用的时候需要的是一个具有Iterator
接口的参数。all
方法会返回一个Promise
对象,这个对象是在all
方法中新建的。all
方法会遍历参数中的所有成员,且会使用Promise.resolve()
方法将每个成员转为一个Promise
对象all
方法中新建的Promise
对象刚返回时只是一个初始状态,其PromiseStatus
和PromiseValue
变量的改变由all
方法的参数来决定:
1、all
方法的参数中的每个成员对应的Promise
对象的状态都为reoslved
时。all
返回的Promise
对象的PromiseStatus
变量值改为resolved
,PromiseValue
变量的值改为一个数组,数组中存储的都是all
方法参数中每个成员对应Promise
对象的回调函数的返回值。
2、all
方法的参数中的每个成员对应的Promise
对象中出现第一个状态为rejected
的Promise
对象A时。all
返回的Promise
对象的PromiseStatus
变量值改为rejected
,PromiseValue
变量的值改为对象A的回调函数的返回值。
all
方法内部代码逻辑可以参考底部Promis
类.
6、Promise.race
race
方法的特性:
race
方法是属于Promise
类的静态方法,方法在调用的时候需要的是一个具有Iterator
接口的参数。race
方法会返回一个Promise
对象,这个对象是在race
方法中新建的。race
方法会遍历参数中的所有成员,且会使用Promise.resolve()
方法将每个成员转为一个Promise
对象race
方法中新建的Promise
对象刚返回时只是一个初始状态,其PromiseStatus
和PromiseValue
变量的改变由race
方法的参数来决定:当race
方法的参数中的所有成员所对应的Promise
对象中出现第一个状态不在是pending的对象A时,将race
方法返回的Promise
对象的PromiseStatus
变量的值改为对象A的状态,PromiseValue
变量的值改为对象A的PromiseValue
变量的值
race
方法内部代码逻辑可以参考底部Promis
类.
Promise微任务何时调用
Promise
的微任务一般都是有then
方法内部产生并被记录下来的,其在两个地方会被加入微任务队列中,当前宏任务执行完毕后,才会去执行微任务队列中的所有微任务。
- 在调用
then
方法时,Promise
对象的状态已经不是pending
了,此时在then
方法中会将刚记录的微任务加入到队列中,但是如果对象状态还处于pending
,那么只会记录,不会加入队列。 - 当
Promise
对象改变pending
状态为其他状态时,会从记录中取出对应状态的微任务加入到队列中。
console.log('宏任务1---开始执行');
var p1 = new Promise(function(RESOLVE,REJECT){
console.log('宏任务1---创建了Promise实例对象 p1');
console.log('宏任务1---注册了延时回调函数。注意:回调函数中的函数体执行代码为一个宏任务');
setTimeout(function(){
console.log('***********************************');
console.log('2秒时间到了,将宏任务2加入宏任务队列');
console.log('***********************************');
console.log('宏任务2---开始执行');
console.log('宏任务2---修改Promise实例对象 p1 的状态为 resolved');
RESOLVE(123);
console.log('宏任务2---当 p1 的状态变为 resolved,时发现 p1 已经提前注册了回调函数,');
console.log('宏任务2---所以要从所有的回调函数中筛选出符合的回调要求的函数,将筛选出来的函数的函数体执行代码作为微任务加入到微任务队列中');
console.log('宏任务2---将p1的回调函数1的函数体执行代码作为宏任务2后的微任务1加入微任务队列中');
console.log('宏任务2---将p1的回调函数2的函数体执行代码作为宏任务2后的微任务2加入微任务队列中');
console.log('宏任务2---将p1的回调函数5的函数体执行代码作为宏任务2后的微任务3加入微任务队列中');
console.log('宏任务2---执行结束');
},2000);
});
var p2 = new Promise(function(RESOLVE,REJECT){
console.log('宏任务1---创建了Promise实例对象 p2');
console.log('宏任务1---注册了延时回调函数。注意:回调函数中的函数体执行代码为一个宏任务');
setTimeout(function(){
console.log('***********************************');
console.log('4秒时间到了,将宏任务3加入宏任务队列');
console.log('***********************************');
console.log('宏任务3---开始执行');
console.log('宏任务3---修改Promise实例对象 p2 的状态为 rejected');
REJECT(321);
console.log('宏任务3---当 p2 的状态变为 rejected,时发现 p2 已经提前注册了回调函数,');
console.log('宏任务3---所以要从所有的回调函数中筛选出符合的回调要求的函数,将筛选出来的函数的函数体执行代码作为微任务加入到微任务队列中');
console.log('宏任务3---将p2的回调函数1的函数体执行代码作为宏任务3后的微任务1加入微任务队列中');
console.log('宏任务3---将p2的回调函数3的函数体执行代码作为宏任务3后的微任务2加入微任务队列中');
console.log('宏任务3---将p2的回调函数4的函数体执行代码作为宏任务3后的微任务3加入微任务队列中');
console.log('宏任务3---将p2的回调函数5的函数体执行代码作为宏任务3后的微任务4加入微任务队列中');
console.log('宏任务3---执行结束');
},4000);
});
var p3 = new Promise(function(RESOLVE,REJECT){
console.log('宏任务1---创建了Promise实例对象 p3');
console.log('宏任务1---修改修改Promise实例对象 p3 的状态为 resolved');
RESOLVE('ABC');
});
var p4 = new Promise(function(RESOLVE,REJECT){
console.log('宏任务1---创建了Promise实例对象 p4');
console.log('宏任务1---修改修改Promise实例对象 p4 的状态为 rejected');
REJECT('CBA');
});
// 因为此时 p1 的状态是pending,所以给p1注册的回调函数都是先记录下来的
console.log('宏任务1---给 p1 注册finally回调函数,记录为p1回调函数1');
p1.finally(()=>{
console.log('宏任务2后的微任务1---开始执行');
console.log('宏任务2后的微任务1---(执行中)')
console.log('宏任务2后的微任务1---执行结束');
});
console.log('宏任务1---给 p1 注册then回调函数,参数一记录为p1回调函数2,参数二记录为p1回调函数3');
p1.then(
(resolveResult) => {
console.log('宏任务2后的微任务2---开始执行');
console.log('宏任务2后的微任务2---(执行中)')
console.log('宏任务2后的微任务2---执行结束');
},
(rejectResult) => {
console.log('p1的状态不是rejected,所以这个函数不会执行');
}
);
console.log('宏任务1---给 p1 注册catch回调函数,记录为p1的回调函数4');
p1.catch((rejectResult)=>{
console.log('p1的状态不是rejected,所以这个函数不会执行');
});
console.log('宏任务1---给 p1 注册finally回调函数,记录为p1回调函数5');
p1.finally(()=>{
console.log('宏任务2后的微任务3---开始执行');
console.log('宏任务2后的微任务3---(执行中)')
console.log('宏任务2后的微任务3---执行结束');
console.log('***********************************');
console.log('这时宏任务2后的所有微任务执行完毕');
console.log('***********************************');
});
// 因为此时 p2 的状态是pending,所以给p2注册的回调函数都是先记录下来的
console.log('宏任务1---给 p2 注册finally回调函数,记录为p2回调函数1');
p2.finally(()=>{
console.log('宏任务3后的微任务1---开始执行');
console.log('宏任务3后的微任务1---(执行中)')
console.log('宏任务3后的微任务1---执行结束');
});
console.log('宏任务1---给 p2 注册then回调函数,参数一记录为p2回调函数2,参数二记录为p2回调函数3');
p2.then(
(resolveResult) => {
console.log('p4的状态不是resolved,所以这个函数不会执行');
},
(rejectResult) => {
console.log('宏任务3后的微任务2---开始执行');
console.log('宏任务3后的微任务2---(执行中)')
console.log('宏任务3后的微任务2---执行结束');
}
);
console.log('宏任务1---给 p2 注册catch回调函数,记录为p2的回调函数4');
p2.catch((rejectResult)=>{
console.log('宏任务3后的微任务3---开始执行');
console.log('宏任务3后的微任务3---(执行中)')
console.log('宏任务3后的微任务3---执行结束');
});
console.log('宏任务1---给 p2 注册finally回调函数,记录为p2回调函数5');
p2.finally(()=>{
console.log('宏任务3后的微任务4---开始执行');
console.log('宏任务3后的微任务4---(执行中)')
console.log('宏任务3后的微任务4---执行结束');
console.log('***********************************');
console.log('这时宏任务3后的所有微任务执行完毕');
console.log('***********************************');
});
// 因为此时 p3 的状态为 resolved ,所以给 p3 注册的回调函数在注册完成后,会自动将函数体执行代码可以作为微任务添加到微任务队列中,
// 当宏任务1执行完毕后,就可以一一执行微任务队列中的任务了
console.log('宏任务1---给 p3 注册finally回调函数。');
p3.finally(()=>{
console.log('宏任务1后的微任务1---开始执行');
console.log('宏任务1后的微任务1---(执行中)')
console.log('宏任务1后的微任务1---执行结束');
});
console.log('宏任务1---因为此时 p3 的状态不是pending,所以将刚注册的回调函数的函数体执行代码作为宏任务1后的微任务1添加进微任务队列。');
console.log('宏任务1---给 p3 注册then回调函数。');
p3.then(
(resolveResult) => {
console.log('宏任务1后的微任务2---开始执行');
console.log('宏任务1后的微任务2---(执行中)')
console.log('宏任务1后的微任务2---执行结束');
},
(rejectResult) => {
console.log('p3的状态不是rejected,所以这个函数不会执行');
}
);
console.log('宏任务1---因为此时 p3 的状态是resolved,所以将刚注册的then方法的参数一回调函数的函数体执行代码作为宏任务1后的微任务2添加进微任务队列。');
console.log('宏任务1---给 p3 注册catch回调函数。因为 p3 状态为resolved,所以catch函数的参数一不会被执行');
p3.catch((rejectResult)=>{
console.log('p3的状态不是rejected,所以这个函数不会执行');
});
console.log('宏任务1---给 p3 注册finally回调函数。');
p3.finally(()=>{
console.log('宏任务1后的微任务3---开始执行');
console.log('宏任务1后的微任务3---(执行中)')
console.log('宏任务1后的微任务3---执行结束');
});
console.log('宏任务1---因为此时 p3 的状态不是pending,所以将刚注册的回调函数的函数体执行代码作为宏任务1后的微任务3添加进微任务队列。');
// 因为此时 p4 的状态为 rejected ,所以给 p4 注册的回调函数在注册完成后,会自动将函数体执行代码可以作为微任务添加到微任务队列中,
// 当宏任务1执行完毕后,就可以一一执行微任务队列中的任务了
console.log('宏任务1---给 p4 注册finally回调函数。');
p4.finally(()=>{
console.log('宏任务1后的微任务4---开始执行');
console.log('宏任务1后的微任务4---(执行中)')
console.log('宏任务1后的微任务4---执行结束');
});
console.log('宏任务1---因为此时 p4 的状态不是pending,所以将刚注册的回调函数的函数体执行代码作为宏任务1后的微任务4添加进微任务队列。');
console.log('宏任务1---给 p4 注册then回调函数。');
p4.then(
(resolveResult) => {
console.log('p4的状态不是resolved,所以这个函数不会执行');
},
(rejectResult) => {
console.log('宏任务1后的微任务5---开始执行');
console.log('宏任务1后的微任务5---(执行中)')
console.log('宏任务1后的微任务5---执行结束');
}
);
console.log('宏任务1---因为此时 p4 的状态是rejected,所以将刚注册的then方法的参数二回调函数的函数体执行代码作为宏任务1后的微任务5添加进微任务队列。');
console.log('宏任务1---给 p4 注册catch回调函数。');
p4.catch((rejectResult)=>{
console.log('宏任务1后的微任务6---开始执行');
console.log('宏任务1后的微任务6---(执行中)')
console.log('宏任务1后的微任务6---执行结束');
});
console.log('宏任务1---因为此时 p4 的状态是rejected,所以将刚注册的回调函数的函数体执行代码作为宏任务1后的微任务6添加进微任务队列。');
console.log('宏任务1---给 p4 注册finally回调函数。');
p4.finally(()=>{
console.log('宏任务1后的微任务7---开始执行');
console.log('宏任务1后的微任务7---(执行中)')
console.log('宏任务1后的微任务7---执行结束');
console.log('***********************************');
console.log('这时宏任务1后的所有微任务执行完毕');
console.log('***********************************');
});
console.log('宏任务1---因为此时 p4 的状态不是pending,所以将刚注册的回调函数的函数体执行代码作为宏任务1后的微任务7添加进微任务队列。');
console.log('宏任务1---执行结束');
Promise类
这里的代码只是还原Promise
类内部的部分逻辑的伪代码。
/*
* 修改 Promise对象 的 PromiseStatus 变量为 resolved
* 修改 Promise对象 的 PromiseValue 变量为 方法的参数的值
*/
let amendPromiseResolved = function(resolvedValue){
// 只有当 Promise对象 的 状态 是 pending 时才可以修改
if (this['PromiseStatus']==='pending') {
// 如果 resolvedValue 参数的值是一个 Promise对象 时,需要等这个对象的状态不处于 pending 时,
// 使用它改变后的 PromiseStatus 和 PromiseValue 变量的值 作为修改的参考
if (resolvedValue instanceof Promise &&
Object.prototype.toString.call(resolvedValue).indexOf('Promise')!=-1) {
// 等待状态不在是 pending 的 Promise对象
let waitChangedPromise = resolvedValue;
// 等待 waitChangedPromise 状态不在是 pending 时,进行修改的 Promise对象
let self = this;
waitChangedPromise.then(
function(resolvedResult){
// 当 waitChangedPromise 对象的状态处于 resolved 时,本函数被调用,
// 此时将 self 对象的 PromiseStatus 变量的值改为 resolved ,
// self 的 PromiseValue 变量的值改为 resolvedResult
amendPromiseResolved.bind(self,resolvedResult)();
},
function(rejectedResult){
// 当 waitChangedPromise 对象的状态处于 rejected 时,本函数被调用,
// 此时将 self 对象的 PromiseStatus 变量的值改为 rejected ,
// self 的 PromiseValue 变量的值改为 rejectedResult
amendPromiseRejected.bind(self,rejectedResult)();
}
);
}else if (resolvedValue.then !== undefined) {
// 如果 resolvedValue 参数的值是一个包含有then方法的对象,
// 那也可以使用then方法作为修改 self 对象的 PromiseStatus 和 PromiseValue 变量的值 的参考
// 被修改的Promise对象
let self = this;
// 使用 amendPromiseResolved 方法修改 self 对象的内部变量
let amendResolve = function(resolvedResult){
amendPromiseResolved.bind(self,resolvedResult)();
};
// 使用 amendPromiseRejected 方法修改 self 对象的内部变量
let amendReject = function(rejectedResult){
amendPromiseRejected.bind(self,rejectedResult)();
}
// 这个then方法内部内部由用户自定义的,何时调用 amendResolve 方法,
// 还是调用 amendReject 方法,由用户自己来决定。
resolvedValue.then(amendResolve,amendReject);
}else{
// 如果 resolvedValue 参数的值不是 Promise对象 时,
// 直接将 this 这个 Promise对象 的 PromiseStatus 变量的值改为 resolved,
// this 的 PromiseValue 变量的值改为 resolvedValue 参数的值。
this['PromiseStatus'] = 'resolved';
this['PromiseValue'] = resolvedValue;
// 因为 this 的状态从 pending 变为 resolved,
// 所以唤醒 this 中记录的 resolvedMicroTasks 数组下的 所有微任务
callNoteMicroTask(this);
}
}
};
/*
* 修改 Promise对象 的 PromiseStatus 变量为 rejected
* 修改 Promise对象 的 PromiseValue 变量为 方法的参数的值
*/
let amendPromiseRejected = function(rejectedValue){
// 只有当 Promise对象 的 状态 是 pending 时才可以修改
if (this['PromiseStatus']==='pending') {
// 不管 rejectedValue 参数的数据类型是什么,哪怕是Promise对象。
// 直接将 this 这个 Promise对象 的 PromiseStatus 变量的值改为 rejected,
// this 的 PromiseValue 变量的值改为 rejectedValue 参数的值。
this['PromiseStatus'] = 'rejected';
this['PromiseValue'] = rejectedValue;
// 因为 this 的状态从 pending 变为 rejected
// 所以唤醒 this 中记录的 rejectedMicroTasks 数组下的 所有微任务
callNoteMicroTask(this);
}
};
/*
* 唤醒参数 Promise对象上 记录过的微任务
*/
let callNoteMicroTask = function(promise){
let status = promise['PromiseStatus']
let microTaskArr;
swtich(status){
case 'pending':
break;
case 'resolved':
// 获取参数 Promise对象 在 resolved 状态下的所有微任务
microTaskArr = promise.note.resolvedMicroTasks;
break;
case 'rejected':
// 获取参数 Promise对象 在 rejected 状态下的所有微任务
microTaskArr = promise.note.rejectedMicroTasks;
break;
}
if(microTaskArr !== null && microTaskArr !== undefined && microTaskArr.length > 0){
/*
* 将 microTaskArr 数组中的所有微任务执行代码按顺序一个个加入到微任务队列中。
* 加入微任务队列中的微任务会从记录中移除
*/
}
}
class Promise{
constructor(paraFun){
// Promise构造函数调用时,必须传递函数对象作为参数。
if (Object.prototype.toString.call(paraFun).indexOf('Function')!=-1) {
// 新建Promise对象 的 PromiseStatus 和 PromiseValue 变量的值分别是 pending 和 undefined
this['PromiseStatus'] = 'pending';
this['PromiseValue'] = undefined;
// 当 Promise对象 处于 pending 状态时调用 then 方法时,会用到这个记录对象
// 记录 所有 形成的微任务。
this.note = {
resolvedMicroTasks:[],
rejectedMicroTasks:[]
}
try{
// 调用构造函数传入的参数函数
// 将 amendPromiseResolved 和 新建Promise对象 绑定生成一个 属于 新建Promise对象 的函数,作为参数一
// 将 amendPromiseRejected 和 新建Promise对象 绑定生成一个 属于 新建Promise对象 的函数,作为参数二
paraFun(
amendPromiseResolved.bind(this),
amendPromiseRejected.bind(this)
);
}catch(error){
// 如果在paraFun方法在调用时抛出错误时
// 直接修改 新建Promise对象 的 PromiseStatus 变量的值为 rejected
// PromiseValue 变量的值为 抛出的错误
amendPromiseRejected.bind(this,error)();
}
}else{
throw new Error('调用Promise构造函数时必须使用函数对象作为参数');
}
}
then(callback1,callback2){
// 要素一:
let self = this; // 调用 then 方法的 Promise对象
// 要素二:
let amendResolve; // 用于修改 新建Promise对象 为 resolved 状态的函数
let amendReject; // 用于修改 新建Promise对象 为 rejected 状态的函数
// 新建一个 Promise对象,其会作为 then 方法的返回值
let p = new Promise((RESOLVE,REJECT) => {
// 将可以修改 新建Promise对象 内部变量 的两个函数导出构造函数,下面有用
amendResolve = RESOLVE;
amendReject = REJECT;
});
// 要素三:
let resolvedCallBack = callback1; // 当 self 对象的状态为 resolved 时会被间接调用的函数
let rejectedCallBack = callback2; // 当 self 对象的状态为 rejected 时会被间接调用的函数
// 两种微任务
let resolvedMicroTask; // 当 self 对象的状态为 resolved 时,根据不同情况修改 新建Promise对象 的 内部变量
let rejectedMicroTask; // 当 self 对象的状态为 rejected 时,根据不同情况修改 新建Promise对象 的 内部变量
if (resolvedCallBack &&
Object.prototype.toString.call(resolvedCallBack).indexOf('Function')!=-1) {
// 当 then 方法的参数一存在,且是一个函数对象,
// 那就把 resolvedCallBack 函数的返回值,作为修改 新建Promise对象 内部变量 的参考。
resolvedMicroTask = function(){
// 本函数对象的 执行代码 代表了一个 微任务
// 本函数对象会先添加到 self 对象下的记录微任务中的对应 resolved 状态的数组中
// 当 self 对象的状态 为 resolved 时,会从记录数组中取出 本函数对象,
// 将函数对象的 执行代码 作为一个 微任务 加入到 微任务队列中
// 这个微任务的目的是以 resolvedCallBack 函数的调用作为参考,去修改 新建Promise对象 内部变量
try{
// resolvedCallBack 函数在调用时,会以 self 的 PromiseValue 变量的值 作为参数
var result = resolvedCallBack(self['PromiseValue']);
// 调用 amendResolve 函数修改 新建Promise对象 的 PromiseStatus 变量的值为 resolved
// 修改 PromiseValue 变量的值以 resolvedCallBack 函数的返回值作为参考
// 即使 result 的数据类型是Promise,但是 amendResolve 函数内部会对其进行特殊处理。
amendResolve(result);
}catch(error){
// 如果 resolvedCallBack 函数在调用时,出现 错误抛出 ,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 rejected
// PromiseValue 变量的值为 抛出的错误
amendReject(error);
}
}
}else{
// 当 then 方法被调用时,参数一不是一个函数对象,
// 那就把 self 对像的 内部变量 作为修改 新建Promise对象 内部变量 的参考
resolvedMicroTask = function(){
// 本函数对象的 执行代码 代表了一个 微任务
// 本函数对象会先添加到 self 对象下的记录微任务中的对应 resolved 状态的数组中
// 当 self 对象的状态 为 resolved 时,会从记录数组中取出 本函数对象,
// 将函数对象的 执行代码 作为一个 微任务 加入到 微任务队列中
// 这个微任务的目的是以 self 对像的 内部变量 作为参考,去修改 新建Promise对象 内部变量
if (self['PromiseStatus'] === 'resolved') {
// self 对象的状态是 resolved 时,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 resolved
// PromiseValue 变量的值为 self 对象的 PromiseValue 变量的值
amendResolve(self['PromisValue']);
}else if (self['PromiseStatus'] === 'rejected') {
// self 对象的状态是 rejected 时,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 rejected
// PromiseValue 变量的值为 self 对象的 PromiseValue 变量的值
amendReject(self['PromisValue']);
}
}
}
if (rejectedCallBack &&
Object.prototype.toString.call(rejectedCallBack).indexOf('Function')!=-1) {
// 当 then 方法的参数二存在,且是一个函数对象,
// 那就把 rejectedCallBack 函数的返回值,作为修改 新建Promise对象 内部变量 的参考。
rejectedMicroTask = function(){
// 本函数对象的 执行代码 代表了一个 微任务
// 本函数对象会先添加到 self 对象下的记录微任务中的对应 rejected 状态的数组中
// 当 self 对象的状态 为 rejected 时,会从记录数组中取出 本函数对象,
// 将函数对象的 执行代码 作为一个 微任务 加入到 微任务队列中
// 这个微任务的目的是以 rejectedCallBack 函数的调用作为参考,去修改 新建Promise对象 内部变量
try{
// rejectedCallBack 函数在调用时,会以 self 的 PromiseValue 变量的值 作为参数
var result = rejectedCallBack(self['PromiseValue']);
// 调用 amendResolve 函数修改 新建Promise对象 的 PromiseStatus 变量的值为 resolved
// 修改 PromiseValue 变量的值以 rejectedCallBack 函数的返回值作为参考
// 即使 result 的数据类型是Promise,但是 amendResolve 函数内部会对其进行特殊处理。
amendResolve(result);
// 虽然 rejectedMicroTask 函数是在状态为 rejected 时被调用,但是这里依然要使用 amendResolve 函数修改内部变量
}catch(error){
// 如果 rejectedCallBack 函数在调用时,出现 错误抛出 ,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 rejected
// PromiseValue 变量的值为 抛出的错误
amendReject(error);
}
}
}else{
// 当 then 方法被调用时,参数二不是一个函数对象,
// 那就把 self 对像的 内部变量 作为修改 新建Promise对象 内部变量 的参考
rejectedMicroTask = function(){
// 本函数对象的 执行代码 代表了一个 微任务
// 本函数对象会先添加到 self 对象下的记录微任务中的对应 rejected 状态的数组中
// 当 self 对象的状态 为 rejected 时,会从记录数组中取出 本函数对象,
// 将函数对象的 执行代码 作为一个 微任务 加入到 微任务队列中
// 这个微任务的目的是以 self 对像的 内部变量 作为参考,去修改 新建Promise对象 内部变量
if (self['PromiseStatus'] === 'resolved') {
// self 对象的状态是 resolved 时,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 resolved
// PromiseValue 变量的值为 self 对象的 PromiseValue 变量的值
amendResolve(self['PromisValue']);
}else if (self['PromiseStatus'] === 'rejected') {
// self 对象的状态是 rejected 时,
// 修改 新建Promise对象 的 PromiseStatus 变量的值为 rejected
// PromiseValue 变量的值为 self 对象的 PromiseValue 变量的值
amendReject(self['PromisValue']);
}
}
}
// 将分别代表了两种状态下的微任务的 resolvedMicroTask 和 rejectedMicroTask 函数记录到 self 对象上
self.note.resolvedMicroTasks[resolvedMicroTasks.length] = resolvedMicroTask;
self.note.rejectedMicroTasks[rejectedMicroTasks.length] = rejectedMicroTask;
if (self['PromiseStatus'] !== 'pending') {
// 如果 self 对象在调用 then 方法时,不处于 pending 状态,
// 那就唤醒 self 中记录的 所有微任务,其实就是将刚形成的微任务直接加入微任务队列中。
callNoteMicroTask(self);
}
// 此时的 新建实例对象p 的内部变量都是初始值。
return p;
}
catch(callBack){
return this.then(null,callBack);
}
finally(callBack){
return this.then(
(resolvedResult)=>{ callBack(); return resolvedResult; },
(rejectResult)=>{ callBack(); throw rejectResult; }
);
// 这是另一种实现方式,目的是为了既实现效果,也要用箭头函数实现?
// let P = this.constructor;
// return this.then(
// value => P.resolve(callback()).then(() => value),
// reason => P.resolve( callback()).then(() => { throw reason })
// );
}
static resolve(resolvedValue){
return new this((RESOLVE,REJECT)=>{
RESOLVE(resolvedValue);
});
}
static reject(rejectedValue){
return new this((RESOLVE,REJECT)=>{
REJECT(rejectedValue);
});
}
static race(arrPromise){
// race静态方法会返回一个 新建Promise对象
// 将可以修改 新建Promise对象 的内部变量的函数引导出来
let resolvP;
let rejectP;
let p = new Promise((RESOLVE,REJECT)=>{
resolvP=RESOLVE;
rejectP=REJECT;
});
for (let arrp of arrPromise){
let promise = Promise.resolve(arrp);
// 给每个Promise对象都设置回调函数,哪个回调先被调用
// 就先用这个回调的状态和返回值去修改 新建Promise对象 的内部变量。
promise.then((resolveValue)=>{
resolvP(resolveValue);
});
promise.catch((rejectValue)=>{
rejectP(rejectValue);
});
}
return p;
}
static all(arrPromise){
// all静态方法会返回一个 新建Promise对象
// 将可以修改 新建Promise对象 的内部变量的函数引导出来
let resolvP;
let rejectP;
let p = new Promise((RESOLVE,REJECT)=>{
resolvP=RESOLVE;
rejectP=REJECT;
});
var pValueArr = [];
let index = -1;
for (let arrp of arrPromise){
let promise = Promise.resolve(arrp);
let pValueArrIndex = ++index;
promise.then((resolveValue)=>{
// 将每个状态为 resolved 的 Promise对象 的 PromiseValue 变量的值进行存储
pValueArr[pValueArrIndex] = resolveValue;
if(pValueArr.length === arrPromise.length){
// 当 pValueArr 存储的 PromiseValue 变量的值的数量等于 Promise对象 的数量时,
// 修改 新建Promise对象 的内部变量
// 修改 PromiseStatus 变量的值为 resolved
// 修改 PromiseValue 变量的值为 pValueArr
resolvP(pValueArr);
};
});
// 只有一有 Promise对象 的状态变为 rejected 时,就修改 新建Promise对象 的内部变量
promise.catch((rejectValue)=>{
// 修改 PromiseStatus 变量的值为 rejected
// 修改 PromiseValue 变量的值为 rejectValue
rejectP(rejectValue);
});
}
return p;
}
}
缺点
- 当我们在进行异步编程的时候,开启异步的代码一般都写在构造函数的参数函数中,参数函数是随着
Promise
对象的创建而执行,所以我们没有办法去终止异步的开启。 Promise
类中,在构造函数的参数函数以及then
方法的参数函数中抛出的错误,我们在Promise
外是无法获取到的。- 构造函数的参数函数的函数体中的代码在执行时,我们没法获取具体执行到哪一步了,直到执行
RESOLVE
函数或者REJECT
函数。