您好,登錄后才能下訂單哦!
這篇文章主要介紹了利用ES6進行Promise封裝的案例,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
原生Promise解析
簡介
promise是異步編程的一種解決方案,比傳統的解決方案--回調函數和事件--更合理和強大。
promise簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,從語法上來說,Promise是一個對象,從它可以獲取異步操作的消息,Promise提供統一的API,各種異步操作都可以用同樣的方法進行處理
特點
對象的狀態不受外界影響,Promise對象代表一個異步操作,有三種狀態:Pendding、fulfilled、rejected。只有異步操作的結果,可以決定當前是哪一種狀態,其他操作都無法改變這個狀態。
一旦狀態改變,就不會在變,任何時候都可以得到這個結果,只有兩種可能:從Pendding變為fulfilled和從Pendding變為rejected。只要這兩種情況發生,狀態就凝固了,會一直保持這個結果,這時就稱為resolved。
利用es6進行Promise封裝
處理同步任務
原生方法調用方式
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) } } }
處理異步任務
原生調用方式
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) }) },(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 }) } } }
處理鏈式調用
原生調用方式
new Promise((resolve,reject)=>{ resolve(1) }).then(res=>{ return res }).then(res=>{ console.log(res) })
鏈式調用思考
原生的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 }) } 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) }) }) }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) } }) } 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'
感謝你能夠認真閱讀完這篇文章,希望小編分享的“利用ES6進行Promise封裝的案例”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。