摘要:當的狀態已經流轉時,回調函數會立即被執行,當還處于狀態時,回調函數被推入相應隊列中等待執行。
概覽
const PENDING = Symbol("PENDING"); const FULFILLED = Symbol("FULFILLED"); const REJECTED = Symbol("REJECTED"); class MyPromise { constructor(fn) {} then(successFn, failFn) {} catch(failFn) {} finally(finalFn){} static resolve(val) {} static reject(val) {} static all(promiseArr) {} static race(promiseArr) {} }
Promise 內部維護著三種狀態 pending、fulfilled 和 rejected,狀態只能從 pending 轉變到 fulfilled,或從 pending 轉變到 rejected 且該轉變不可逆。
Promise 主要提供了三個實例方法 then,catch,finally,和4個靜態方法 resolve,reject,all,race。所有方法都都返回一個Promise對象。
構造函數constructor(fn) { this.fulfilledQueue = []; this.rejectedQueue = []; this._status = PENDING; this._value = null; // 執行成功隊列中的回調函數 const handleFulfilledQueue = () => { while(this.fulfilledQueue.length) { let fulfiledFn = this.fulfilledQueue.shift(); fulfiledFn(this._value); }; }; // 執行失敗隊列中的回調函數 const handleRejectedQueue = () => { while(this.rejectedQueue.length) { let rejectedFn = this.rejectedQueue.shift(); rejectedFn(this._value); }; }; // 完成狀態轉變,執行回調隊列中的回調函數 const _resolve = (val) => { const fn = () => { if(this._status !== PENDING) { return; } if(val instanceof MyPromise) { val.then((res) => { this._status = FULFILLED; this._value = res; handleFulfilledQueue(); }, (err) => { this._status = REJECTED; this._value = err; handleRejectedQueue(); }); } else { this._status = FULFILLED; this._value = val; handleFulfilledQueue(); } } // 保證promise 回調函數一定是在同步任務之后執行; setTimeout(fn, 0); } // 完成狀態Pending到REJECTED的轉變,執行rejected隊列中的回調函數 const _reject = (val) => { const fn = () => { if(this._status !== PENDING) { return; } this._status = REJECTED; this._value = val; handleRejectedQueue(); } setTimeout(fn, 0); } try { // 處理外部傳入函數執行異常 fn(_resolve, _reject); } catch(e) { return _reject(e); } }
Promise 構造函數接收一個函數執行器作為參數,該執行器的兩個參數 _resolve、_reject均為函數類型,由 Promise 內部實現。執行器在 Promise 構造函數中被立即執行。
注意: MyPromise 使用 Timeout 實現異步,使得 MyPromise 只能添加 macrotask,實際上原生的Promise 是 microtask
then 方法then(successFn, failFn) { return new MyPromise((resolve, reject) => { // 執行成功時的回調函數 const handleSucess = (fn) => { try { if(typeof fn === "function") { const res = fn(this._value); if(res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } } else { resolve(this._value) } } catch(e){ reject(e); } } // 執行失敗時的回調函數 const handleFail = (fn) => { try { if(typeof fn === "function") { const res = fn(this._value); if(res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } } else { reject(this._value); } } catch(e) { reject(e); } } switch(this._status){ case PENDING: // 異步任務尚未完成,將回調函數推入相應隊列 this.fulfilledQueue.push(() => { handleSucess(successFn); }); this.rejectedQueue.push(() => { handleFail(failFn); }); break; case FULFILLED: // 異步任務成功完成,執行成功回調函數 handleSucess(successFn); break; case REJECTED: // 異步任務已失敗,執行失敗回調函數 handleFail(failFn); break; default: console.log("Promise error status:", this._status); break; }; }); }
then 方法是 Promise 的一個主要方法,catch 和 finally 都可以用 then 來實現。當 Promise 的狀態已經流轉時,回調函數會立即被執行,當 Promise 還處于 Pending 狀態時,回調函數被推入相應隊列中等待執行。
完整代碼class MyPromise { constructor(fn) { this.fulfilledQueue = []; this.rejectedQueue = []; this._status = PENDING; this._value = null; const handleFulfilledQueue = () => { while(this.fulfilledQueue.length) { let fulfiledFn = this.fulfilledQueue.shift(); fulfiledFn(this._value); }; }; const handleRejectedQueue = () => { console.log(this.rejectedQueue); while(this.rejectedQueue.length) { let rejectedFn = this.rejectedQueue.shift(); rejectedFn(this._value); }; }; // 完成狀態轉變,執行回調隊列中的回調函數 const _resolve = (val) => { const fn = () => { if(this._status !== PENDING) { return; } if(val instanceof MyPromise) { val.then((res) => { this._status = FULFILLED; this._value = res; handleFulfilledQueue(); }, (err) => { this._status = REJECTED; this._value = err; handleRejectedQueue(); }); } else { this._status = FULFILLED; this._value = val; handleFulfilledQueue(); } } setTimeout(fn, 0); } // 完成狀態Pending到REJECTED的轉變,執行rejected隊列中的回調函數 const _reject = (val) => { const fn = () => { if(this._status !== PENDING) { return; } this._status = REJECTED; this._value = val; handleRejectedQueue(); } setTimeout(fn, 0); } try { // 處理外部傳入函數執行異常 fn(_resolve, _reject); } catch(e) { return _reject(e); } } then(successFn, failFn) { return new MyPromise((resolve, reject) => { // 執行成功時的回調函數 const handleSucess = (fn) => { try { if(typeof fn === "function") { const res = fn(this._value); if(res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } } else { resolve(this._value) } } catch(e){ reject(e); } } // 執行失敗時的回調函數 const handleFail = (fn) => { try { if(typeof fn === "function") { const res = fn(this._value); if(res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } } else { reject(this._value); } } catch(e) { reject(e); } } switch(this._status){ case PENDING: // 異步任務尚未完成,將回調函數推入相應隊列 this.fulfilledQueue.push(() => { handleSucess(successFn); }); this.rejectedQueue.push(() => { handleFail(failFn); }); break; case FULFILLED: // 異步任務成功完成,執行成功回調函數 handleSucess(successFn); break; case REJECTED: // 異步任務已失敗,執行失敗回調函數 handleFail(failFn); break; default: console.log("Promise error status:", this._status); break; }; }); } catch(failFn) { return this.then(null, failFn); } finally(finalFn){ return this.then(finalFn, finalFn); } static resolve(val) { if(val instanceof MyPromise) { return val; } else { return new MyPromise((resolve, reject) =>{ resolve(val); }); } } static reject(val) { return new MyPromise((resolve, reject) => { reject(val); }); } static all(promiseArr) { return new Promise((resolve, reject) =>{ const len = promiseArr.length; let count = 0; let result = []; for(let i = 0; i < len; i++) { promiseArr[i].then((val) => { count++; result.push[val]; if(count === len){ resolve(result); } }, (err) => { reject(err); }); } }); } static race(promiseArr) { return new Promise((resolve, reject) =>{ const len = promiseArr.length; for(let i = 0; i < len; i++) { promiseArr[i].then((val) => { resolve(val); }, (err) => { reject(err); }); } }); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103251.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發生了什么這是一篇開發的科普類文章,涉及到優化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網絡基礎知識之 HTTP 協議 詳細介紹 HTT...
摘要:執行的時候呢即可如何處理鏈式的且保證順序每個后面鏈一個對象該對象包含子三個屬性當父狀態改變完畢執行完相應的的時候呢,拿到子在等待這個子狀態改變,在執行相應的。 promise源碼分析 初級入門以及如何使用請看 阮一峰promise對象講解 先上一坨代碼,后面我們要基于這坨代碼來實現自定義promise 原始方法 setTimeout(function(){ var a=100...
摘要:實現的一個簡單的如果有錯誤的地方,希望大家能夠不吝賜教僅實現及方法最下方有完整代碼開始一個對象接收的是一個這個接收兩個參數當我們在內執行或的時候,就會調用內定義的和函數然后,和函數會改變的狀態所以它應該是像下面這樣的保存值記錄狀態為,為,為 實現的一個簡單的ES6 Promise(如果有錯誤的地方,希望大家能夠不吝賜教) 僅實現Promise及.then方法最下方有完整代碼 開始 一個...
摘要:主要邏輯本質上還是回調函數那一套。通過的判斷完成異步和同步的區分。 主要邏輯: 本質上還是回調函數那一套。通過_subscribers的判斷完成異步和同步的區分。通過 resolve,reject -> publish -> invokeCallback -> resolve,reject的遞歸和下一條then的parent是上一條的child來完成then鏈的流轉 同步情況...
閱讀 2472·2021-11-24 09:39
閱讀 3518·2019-08-30 15:53
閱讀 594·2019-08-29 15:15
閱讀 2903·2019-08-26 13:23
閱讀 3212·2019-08-26 10:48
閱讀 643·2019-08-26 10:31
閱讀 748·2019-08-26 10:30
閱讀 2359·2019-08-23 18:32