您好,登錄后才能下訂單哦!
這篇“JavaScript怎么實現簡易的Promise對象”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript怎么實現簡易的Promise對象”文章吧。
實現一個簡易的Promise對象,我們首先要了解幾個相關的知識點:
Promise對象的狀態: pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
Promise的參數: Promise構造函數接收一個函數作為參數,函數內部有兩個參數,分別是resolve和reject,這兩個參數是兩個函數,由JS引擎提供,不需要我們部署。reslove函數
的作用是將Promise對象的狀態由 'pending' 狀態變為 'resolved'狀態即('fulfilled'狀態),方便與參數名對應,reject函數
的作用是將Promise對象的狀態由 'pending' 狀態變為 'rejected'狀態。
但是我們應該注意的是,Promise對象的狀態一經改變,就不再發生改變(即pending
--> resolved
|| pending
--> rejected
其中任意一種發生改變之后,Promise對象的狀態將不再發生改變)
let p1 = new Promise((resolve, reject) => { resolve('成功'); reject('失敗'); throw('報錯'); //相當于reject() }) console.log(p1);
讓我們看看三種狀態的打印的結果分別是什么吧
class myPromise { constructor(executor) { this.status = 'pending'; // 變更promise的狀態 this.value = null; executor(this.resolve, this.reject); // new 一個myPromise 得到的實例對象里面有兩個函數 } resolve(value) { if (this.status !== 'pending') return; this.status = 'fulfilled'; // 變更promise的狀態 this.value = value; } reject(reason) { if (this.status !== 'pending') return this.status = 'rejected'; this.value = reason; } }
貌似這么寫代碼邏輯也說得通,那么讓我們看一下實現的效果:
看到這里,不難想到我們的resolve和reject的兩個方法的this
指向出現了問題,我們仔細看看不難發現,這兩個方法被我們作為實參放到了構造器函數,此時this的指向是指向了構造器函數,而不是我們寫的myPromise這個構造函數身上,那只需要bind
顯示綁定一下this 的指向就可以解決了。
executor(this.resolve.bind(this), this.reject.bind(this))
并且myPromise的狀態一經變更也不再改變,是不是有一點原裝Promise的味道了。但是在Promise里面還有一個錯誤捕捉機制,只要promise里面執行的邏輯報錯了,就需要走reject邏輯,將錯誤拋出來,那我們只需要使用try catch來實現就可以。
try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error) }
這樣我們就實現了極簡版的Promise對象,但是通常情況下我們都是使用Promise對象來處理異步的問題,說到異步,那不得不提起Promise.prototype.then()
這個方法了,then
方法返回的是一個新的Promise實例
(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調用另一個then方法。
then方法的第一個參數是`resolved狀態的回調函數`,第二個參數是`rejected狀態的回調函數`,它們都是可選的。
當promise的狀態為'fulfilled'會執行第一個回調函數,當狀態為'rejected'時執行第二個回調函數。
必須等到Promise的狀態變更過一次之后,狀態為'fulfilled'或者'rejected',才去執行then里面的邏輯。
.then支持鏈式調用,下一次.then受上一次.then執行結果的影響。
知道以上這幾點,我們就可以嘗試如何實現.then方法了
class myPromise { constructor(executor) { this.status = 'pending'; this.value = null; this.onFulfilledCallbacks = []; // 用來保存成功的回調(處理異步) this.onRejectedCallbacks = []; // 用來保存失敗的回調(處理異步) try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error) } } resolve(value) { if (this.status !== 'pending') return; this.status = 'fulfilled'; this.value = value; // 調用then里面的回調 while (this.onFulfilledCallbacks.length) { // 當異步成功回調數組中存在回調函數,那就執行 this.onFulfilledCallbacks.shift()(this.value) } } reject(reason) { if (this.status !== 'pending') return this.status = 'rejected'; this.value = reason; while (this.onRejectedCallbacks.length) { // 當異步失敗回調數組中存在回調函數,那就執行 this.onRejectedCallbacks.shift()(this.value) } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val // 判斷.then的第一個參數是不是一個函數,如果不是就直接作為結果返回 onRejected = typeof onRejected === 'function' ? onRejected : val => { throw val } // 判斷.then的第二個參數是不是一個函數,如果不是就直接作為錯誤返回 var thenPromise = new myPromise((resolve, reject) => { // 因為.then返回的是一個心的Promise對象 const resolvePromise = callback => { // 用于判斷回調函數的類型 setTimeout(() => { // 讓整個回調函數比同步代碼晚一點執行,官方不是使用setTimeout實現 try { const x = callback(this.value); if (x === thenPromise) { // 你正在返回自身 throw new Error('不允許返回自身!'); } if (x instanceof myPromise) { // 返回的是一個Promise對象 x.then(resolve, reject); } else { // 直接返回一個值,作為resolve的值,傳遞給下一個.then resolve(x); } } catch (error) { reject(error); throw new Error(error) } }) } if (this.status === 'fulfilled') { resolvePromise(onFulfilled) } else if (this.status === 'rejected') { resolvePromise(onRejected) } else if (this.status === 'pending') { this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled)); this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected)); } }) return thenPromise } }
以上就是關于“JavaScript怎么實現簡易的Promise對象”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。