書接上回
8.指定多個回調(diào)
這個是什么意思呢? 在原生Promise
中有這樣一個特性.
let p = new Promise((resolve,reject)=>{
//異步調(diào)用
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
指定多個回調(diào)后,狀態(tài)改變之后,這些回調(diào)全部都會執(zhí)行.我們就是要實(shí)現(xiàn)的這個功能.
在之前保存回調(diào)函數(shù)的時(shí)候,我們使用的是對象來保存的.而如果想要保存多個回調(diào)函數(shù),就需要用到數(shù)組來保存.
修改后的代碼如下:
function PromiseA(executor){
//添加屬性
this.PromiseState = "pending";
this.PromiseResult = null;
//-------------- 修改的代碼-----------------
this.callbacks = [];
//-------------- 修改的代碼-----------------
//預(yù)先保存實(shí)例對象的this值
const self = this;
//resolve函數(shù)
function resolve(data){
//判斷狀態(tài)
if(self.PromiseState !== "pending"){
return ;
}
//1.修改對象的狀態(tài)(PromiseState)
self.PromiseState = "fulfilled";
//2.設(shè)置對象的結(jié)果值(PromiseResult)
self.PromiseResult = data;
//-------------- 修改的代碼-----------------
//調(diào)用成功的回調(diào)函數(shù)
self.callback.forEach(item=>{
item.onResolved(data);
})
//-------------- 修改的代碼-----------------
}
function reject(data){
//判斷狀態(tài)
if(self.PromiseState !== "pending"){
return ;
}
//1.修改對象的狀態(tài)(PromiseState)
self.PromiseState = "rejected";
//2.設(shè)置對象的結(jié)果值(PromiseResult)
self.PromiseResult = data;
//-------------- 修改的代碼-----------------
//調(diào)用失敗的回調(diào)函數(shù)
self.callback.forEach(item=>{
item.onRejected(data);
})
//-------------- 修改的代碼-----------------
}
//處理 throw 拋出的錯誤
try{
//同步調(diào)用一下
executor(resolve,reject);
}catch (e){
//通過調(diào)用reject函數(shù),它的內(nèi)部可以修改狀態(tài)的和賦值
//所以我們這里可以把錯誤直接傳進(jìn)去就可以了.
reject(e);
}
}
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//調(diào)用 成功 回調(diào)函數(shù)
if(this.PromiseState === "fulfilled"){
onResolved(this.PromiseResult);
}
//調(diào)用失敗的回調(diào)函數(shù)
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//-------------- 修改的代碼-----------------
//保存回調(diào)函數(shù)
this.callbacks.push({
onResolved,
onRejected
});
//-------------- 修改的代碼-----------------
}
}
然后在callbacks
調(diào)用的地方改為數(shù)組遍歷的方式進(jìn)行調(diào)用.
9.同步任務(wù) then 返回結(jié)果的實(shí)現(xiàn)
let p = new Promise((resolve,reject)=>{
resolve("OK");
});
const result = p.then(value=>{
console.log(111)
},reason => {
console.log(reason)
})
console.log(result)
看官方的實(shí)現(xiàn), result
的結(jié)果由p.then
的回調(diào)函數(shù)的執(zhí)行結(jié)果決定.
如果構(gòu)造函數(shù)中成功,就執(zhí)行第一個函數(shù),那就由第一個函數(shù)決定.否則就由第二個決定.
它會返回一個Promise對象,而Promise對象的結(jié)果又取決于 回調(diào)函數(shù)的返回值.
其中又分為三種情況:
- 返回非
Promise
對象的,比如123,ok
,不返回就是undefined
,那么它默認(rèn)會執(zhí)行返回成功的Promise
對象, - 返回
Promise
對象的,則由這個對象決定狀態(tài),如果這個這個對象是成功的,那么外部result
就是成功,如果失敗的,那么外部就是失敗的. - 如果拋出錯誤,那么外部對象就是失敗的.
我們一步一步的來解決上訴的問題:
9.1 既然返回結(jié)果是一個Promise,安排
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
return new PromiseA((resolve,reject)=>{
//調(diào)用 成功 回調(diào)函數(shù)
if(this.PromiseState === "fulfilled"){
onResolved(this.PromiseResult);
}
//調(diào)用失敗的回調(diào)函數(shù)
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//保存回調(diào)函數(shù)
this.callbacks.push({
onResolved,
onRejected
});
}
})
}
我們通過new PromiseA
來包裹一下then
方法中的處理函數(shù). 這一步和官方的Promise
的使用很像,
let p = new Promise((resolve,reject)=>{
//異步調(diào)用
setTimeout(()=>{
resolve("OK");
},100)
});
它的里面通過調(diào)用resolve
和reject
來實(shí)現(xiàn)狀態(tài)的改變.
所以我們這里也可以通過調(diào)用new PromiseA
時(shí)自帶的resolve
和reject
函數(shù)來改變返回的PromiseA
的狀態(tài).
而返回的PromiseA
的狀態(tài)又是取決于回調(diào)函數(shù)的結(jié)果.結(jié)果在哪里?
當(dāng)然是在onResolved(this.PromiseResult)
里.
所以
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//調(diào)用 成功 回調(diào)函數(shù)
if(this.PromiseState === "fulfilled"){
//-------------- 修改的代碼-----------------
let result = onResolved(this.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
//-------------- 修改的代碼-----------------
}
//調(diào)用失敗的回調(diào)函數(shù)
if(this.PromiseState === "rejected"){
//...
}
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//...
}
})
}
我們拿到 result
的結(jié)果.
let result = onResolved(this.PromiseResult);
它就是then
方法執(zhí)行第一個回調(diào)函數(shù)的返回結(jié)果,來判斷它是否為PromiseA
的對象.
如果不是,按照我們上面整理出的規(guī)則,就是成功的狀態(tài),所以通過調(diào)用外部對象的resolve
來進(jìn)行改變.
如果判斷對象是Promise
呢 ?
返回Promise
對象的,則由這個對象決定狀態(tài),如果這個這個對象是成功的,那么外部result
就是成功,如果失敗的,那么外部就是失敗的.
那么怎么拿到這個返回Promise
對象的狀態(tài)呢?
我們知道當(dāng)Promise
對象一旦狀態(tài)發(fā)生改變,它就會回調(diào)它的then
方法中的回調(diào).所以我們這里自己去調(diào)用它的then
方法.
PromiseA.prototype.then = function (onResolved,onRejected){
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//調(diào)用 成功 回調(diào)函數(shù)
if(this.PromiseState === "fulfilled"){
let result = onResolved(this.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//-------------- 修改的代碼-----------------
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
//-------------- 修改的代碼-----------------
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}
//調(diào)用失敗的回調(diào)函數(shù)
if(this.PromiseState === "rejected"){
//...
}
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//...
}
})
}
我們通過在它的內(nèi)部調(diào)用 resolve
來修改外部 我們創(chuàng)建的那個Promise
對象的狀態(tài).
最后還有一個的狀態(tài)就是錯誤的處理,我們只需要try catch
一下就可以了
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//調(diào)用 成功 回調(diào)函數(shù)
if(this.PromiseState === "fulfilled"){
//-------------- 修改的代碼-----------------
try{
//-------------- 修改的代碼-----------------
let result = onResolved(this.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
//-------------- 修改的代碼-----------------
}catch (e){
reject(e);
}
//-------------- 修改的代碼-----------------
}
//調(diào)用失敗的回調(diào)函數(shù)
if(this.PromiseState === "rejected"){
onRejected(this.PromiseResult);
}
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//保存回調(diào)函數(shù)
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: []
}
可以看到結(jié)果發(fā)生了改變
10 異步任務(wù) then 返回結(jié)果
這一次我們解決的是
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("OK");
})
});
const result = p.then(value=>{
console.log(111)
},reason => {
console.log(reason)
})
console.log(result)
通過異步調(diào)用resolve
來執(zhí)行修改內(nèi)部的狀態(tài).還記得之前我們處理異步的時(shí)候是在哪里嗎?
通過判斷狀態(tài)PromiseState
為pending
,把回調(diào)函數(shù)onResolved
和onRejected
保存到實(shí)例對象的callbacks
上.
然后在未來改變的那一刻 調(diào)用 這些函數(shù),來實(shí)現(xiàn)狀態(tài)的改變.
而我們現(xiàn)在也同樣需要在這里進(jìn)行處理.它的區(qū)別其實(shí)和上面同步的不大,只不過一個是未來調(diào)用的.一個是當(dāng)下調(diào)用的.
我們把pending
狀態(tài)下的回調(diào)函數(shù)做一下處理:
//添加pending狀態(tài)的處理
if(this.PromiseState === "pending"){
//保存回調(diào)函數(shù)
this.callbacks.push({
onResolved:function (){
//執(zhí)行成功的回調(diào)函數(shù)
let result = onResolved(this.PromiseResult);
if(result instanceof PromiseA){
}else{
resolve(result);
}
},
onRejected:function (){
}
});
}
當(dāng)onResolved
這個函數(shù)在未來被調(diào)用的時(shí)候,this.PromiseResult
這個值就無法拿到了,因?yàn)檫@里不再是對象調(diào)用,發(fā)生了隱式綁定的情況.
而是脫離了當(dāng)前執(zhí)行上下文環(huán)境,所以我們這里需要利用詞法作用域的特性,設(shè)置一個self
來處理
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//調(diào)用 成功 回調(diào)函數(shù)
if(self.PromiseState === "fulfilled"){
//...
}
//調(diào)用失敗的回調(diào)函數(shù)
if(self.PromiseState === "rejected"){
//...
}
//添加pending狀態(tài)的處理
if(self.PromiseState === "pending"){
//保存回調(diào)函數(shù)
self.callbacks.push({
onResolved:function (){
try{
let result = onResolved(self.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}catch (e){
reject(e);
}
},
onRejected:function (){
try{
let result = onRejected(self.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}catch (e){
reject(e);
}
}
});
}
})
}
異步任務(wù)的執(zhí)行回調(diào)處理其實(shí)和同步的一樣,區(qū)別僅僅只是未來執(zhí)行的時(shí)機(jī)而已.
所以在未來改變狀態(tài)的時(shí)候,我們的外部Promise
對象的狀態(tài)還是取決于它then
方法回調(diào)函數(shù)的返回值.
- 如果是非
Promise
對象,則狀態(tài)為成功, - 如果是
Promise
對象,則狀態(tài)取決于這個對象的狀態(tài),所以我們需要調(diào)用它的then
方法,給它添加上回調(diào)函數(shù),在回調(diào)函數(shù)中去修改外部對象的狀態(tài) - 就是處理一下錯誤
11 優(yōu)化一下then 函數(shù)
發(fā)現(xiàn)在同步任務(wù)中 還有一個rejected
狀態(tài)沒有處理,而它的邏輯又和fulfilled
狀態(tài)的一樣,區(qū)別只是調(diào)用不同的方法而已:
//調(diào)用失敗的回調(diào)函數(shù)
if(self.PromiseState === "rejected"){
try{
let result = onRejected(self.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}catch (e){
reject(e);
}
}
是不是發(fā)現(xiàn)上面的這段代碼重復(fù)了太多次,我們優(yōu)化一下,把這個方法統(tǒng)一成一個函數(shù):
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//抽象成一個函數(shù)
function callback(type){
try{
let result = type(self.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}catch (e){
reject(e);
}
}
//調(diào)用 成功 回調(diào)函數(shù)
if(self.PromiseState === "fulfilled"){
callback(onResolved);
}
//調(diào)用失敗的回調(diào)函數(shù)
if(self.PromiseState === "rejected"){
callback(onRejected);
}
//添加pending狀態(tài)的處理
if(self.PromiseState === "pending"){
//保存回調(diào)函數(shù)
self.callbacks.push({
onResolved:function (){
callback(onResolved);
},
onRejected:function (){
callback(onRejected);
}
});
}
})
}