深度解析利用ES6進行Promise封裝總結

這篇文章主要介紹瞭如何利用ES6進行Promise封裝總結,文中通過示例代碼介紹的非常詳細,寫的十分的全面細緻,具有一定的參考價值,對此有需要的朋友可以參考學習下。如有不足之處,歡迎批評指正。

深度解析利用ES6進行Promise封裝總結

原生Promise解析

簡介

  • promise是異步編程的一種解決方案,比傳統的解決方案--回調函數和事件--更合理和強大。
  • promise簡單說就是一個容器,裡面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,從語法上來說,Promise是一個對象,從它可以獲取異步操作的消息,Promise提供統一的API,各種異步操作都可以用同樣的方法進行處理

特點

對象的狀態不受外界影響,Promise對象代表一個異步操作,有三種狀態:Pendding、fulfilled、rejected。只有異步操作的結果,可以決定當前是哪一種狀態,其他操作都無法改變這個狀態。

一旦狀態改變,就不會在變,任何時候都可以得到這個結果,只有兩種可能:從Pendding變為fulfilled和從Pendding變為rejected。只要這兩種情況發生,狀態就凝固了,會一直保持這個結果,這時就稱為resolved。

1.利用es6進行Promise封裝

2.處理同步任務

3.原生方法調用方式

new Promise((resolve,reject)=>{
resolve(1)
}).then(res=>{
console.log(res) //1
})

同步封裝思考

1.由調用方式可見Promise是一個類

2.它接收一個回調函數,這個回調函數接受resolve和reject方法作為參數

3.當狀態改變後執行then方法,並將resolve或reject的結果作為then方法接受回調函數的參數

class Mypromise{
constructor(callback){
this.status='pendding'
//成功結果
this.s_res = null
// 失敗結果
this.f_res = null
callback((arg)=>{ // 使用箭頭函數this不會丟失
// 改變狀態為成功
this.status = 'fulfilled'
this.s_res = arg
},(arg)=>{
// 改變狀態為失敗
this.status = 'rejected'
this.f_res = arg
})

}
then(onresolve,onreject){
if(this.status === 'fulfilled'){ // 當狀態為成功時
onresolve(this.s_res)
}else if(this.status === 'rejected'){ // 當狀態為失敗時
onreject(this.f_res)
}//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力
}
}

處理異步任務

原生調用方式

new Promise((resolve,reject)=>{
setTimeOut(()=>{
resolve(1)
},1000)
}).then(res=>{
console.log(res)
})

異步封裝思考

1.根據js執行機制,setTimeOut屬於宏任務,then回調函數屬於微任務,當主線程執行完成後,會從異步隊列中取出本次的微任務先執行。

2.也就是說,then方法執行時,狀態還沒有改變,所有我們需要將then方法執行的回調保存起來,等到異步代碼執行完成後,在統一執行then方法的回調函數

class Mypromise{ 

constructor(callback){
this.status='pendding'
//成功結果
this.s_res = null
// 失敗結果
this.f_res = null
this.query = [] // ++
callback((arg)=>{ // 使用箭頭函數this不會丟失
// 改變狀態為成功
this.status = 'fulfilled'
this.s_res = arg
// 當狀態改變後,統一執行then方法的回調
this.query.forEach(item=>{
item.resolve(arg)
})//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力
},(arg)=>{
// 改變狀態為失敗
this.status = 'rejected'
this.f_res = arg
// 當狀態改變後,統一執行then方法的回調
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
if(this.status === 'fulfilled'){ // 當狀態為成功時
onresolve(this.s_res)
}else if(this.status === 'rejected'){ // 當狀態為失敗時
onreject(this.f_res)
}else{ // ++ 狀態沒有改變
this.query.push({ // 保存回調函數到隊列中
resolve:onresolve,
reject:onreject
})//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力

}
}
}

處理鏈式調用

原生調用方式

new Promise((resolve,reject)=>{
resolve(1)
}).then(res=>{
return res
}).then(res=>{
console.log(res)
})//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力

鏈式調用思考

原生的Promise對象的then方法,返回的也是一個Promise對象,一個新的Promise才能支持鏈式調用

下一個then方法可以接受上一個then方法的返回值作為回調函數的參數

主要考慮上一個then方法的返回值:

1.Promise對象/具有then方法的對象

2.其他值

第一個then方法返回一個Promise對象,它的回調函數接受resFn和rejFN兩個回調函數作為參數,把成功狀態的處理封裝為handle函數,接受成功的結果作為參數

在handle函數,根據onresolve返回值的不同做出不同的處理

class Mypromise{
constructor(callback){
this.status='pendding'
//成功結果
this.s_res = null
// 失敗結果
this.f_res = null
this.query = [] // ++
callback((arg)=>{ // 使用箭頭函數this不會丟失
// 改變狀態為成功
this.status = 'fulfilled'
this.s_res = arg
// 當狀態改變後,統一執行then方法的回調
this.query.forEach(item=>{
item.resolve(arg)
})
},(arg)=>{
// 改變狀態為失敗
this.status = 'rejected'
this.f_res = arg
// 當狀態改變後,統一執行then方法的回調
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
return new Mypromise((resFN,rejFN)=>{
if(this.status === 'fulfilled'){ // 當狀態為成功時
handle(this.s_res)
}else if(this.status === 'rejected'){ // 當狀態為失敗時
errBack(this.f_res)
}else{ // ++ 狀態沒有改變
this.query.push({ // 保存回調函數到隊列中
resolve:onresolve,
reject:onreject

})
} //在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力
function handle(value){
// 當then方法的onresolve方法有返回值時,保存其返回值,沒有使用其保存的值
let returnVal = onresolve instanceof Function && onresolve(value) || value
// 如果onresolve方法返回的是promise對象,則調用其then方法
if(returnVal&&returnVal['then'] instanceof Function){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}
function errBack(reason){
if(onreject instanceof Function){
let returnVal = reject(reason)
if(typeof returnVal !== 'undenfined' && returnVal['then'] instanceof Function){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}else{
rejFN(reason)
}
}
})
}
}

Promise.all和Promise.race方法

原生調用方式

Promise.all方法接受一個數組,數組中的每一項都是一個Promise實例,只有數組中的所有Promise實例的狀態都變為fulfilled時,此時整個狀態才會變成fulfilled,此時數組中所有Promise實例的返回值組成一個新的數組,進行傳遞。

Promise.race方法和Promise.all方法一樣,如果不是Promise實例,就會先調用Promise.resolve方法,將參數轉為Promise實例,在進行下一步處理。

只要數組中有一個參數的狀態變為fulfilled就會進行傳遞

// 將現有對象轉換為Promise對象
Mypromise.resolve = (arg)=>{
if(typeof arg == 'undefined' || arg==null){ // 不帶有任何參數
return new Mypromise(resolve=>{
resolve(arg)
})
}else if(arg instanceof Mypromise){ // 是一個Mypromise實例
return arg
}else if(arg['then'] instanceof Function){ // 具有then方法的對象
return new Mypromise((resolve,reject)=>{
arg.then(res=>{
resolve(res)
},err=>{
reject(err)
})//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力
})
}else{ // 參數不是具有then方法的對象,或根本不是對象
return new Mypromise(resolve=>{
resolve(arg)
})
}
}

Mypromise.all = (arr)=>{
if(!Array.isArray(arr)){
throw new TypeError('參數必須是一個數組')
}
return new Mypromise((resolve,reject)=>{
let i=0,result=[]
next()
functon next(){
// 如果不是Mypromise實例需要轉換
Mypromise.resolve(arr[i]).then(res=>{
result.push(res)
i++
if(i===arr.length){
resolve(result)
}else{
next()
}
},reject)
}
})
}//在此我向大家推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提升思維能力
Mypromise.race = (arr)=>{
if(!Array.isArray(arr)){
throw new TypeError('參數必須是一個數組')
}
return new Mypromise((resolve,reject)=>{
let done = false
arr.forEach(item=>{
Mypromise.resolve(item).then(res=>{
if(!done){
resolve(res)
done = true
}
},err=>{
if(!done){
reject(res)
done = true
}
})
})
})
}

處理Mypromise狀態確定不能改變的特性

在重寫callback中的resolve和reject方法執行前,先判斷狀態是否為'pendding'

結語

感謝您的觀看,如有不足之處,歡迎批評指正。

對前端的技術,前端全棧技術感興趣的同學關注我的頭條號,並在後臺私信發送關鍵字:“前端”即可獲取免費的前端開發攻城師學習資料

知識體系已整理好,歡迎免費領取。還有視頻分享可以免費獲取。關注我,可以獲得沒有的經驗哦!


分享到:


相關文章: