手寫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);
}
}
對應的代碼在每一個小節中都有詳細的介紹,務必注意搞清邏輯關系,實作起來就會很靈活輕松! 后續異步執行功能繼續更新封裝,敬請期待,感謝觀看!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/261740.html
標籤:其他
