摘要:開始前的實現原理已經在規范解讀及實現細節一中說的很清楚了,這里將詳細分析規范中的解析過程,最后會實現一個并提供用于測試的代碼方法分析這里的調用會產生一個新的不同實例對于上一級的終值會作為的參數被傳入對于如果返回一個返回一個那么的狀態和值由決
開始前
Promise的實現原理已經在 Promise 規范解讀及實現細節 (一) 中說的很清楚了,這里將詳細分析 Promises/A+規范 中的Promise解析過程,最后會實現一個 Promise 并提供用于測試的代碼
then 方法分析promise.then(fn1).then(fn2).then(fn3) 這里 promise.then() 的調用會產生一個新的promise(不同實例)
對于 then(fn) 上一級 promise 的終值會作為 fn 的參數被傳入
對于 then(fn) 如果 then 返回一個 promise1,fn 返回一個 promise2 那么 promise1 的狀態和值由 promise2 決定
對于 then(fn) 如果 then 返回一個 promise1,fn 返回一個 promise2 我們想依賴于promise2 的調用會被添加到 promise1中
如何讓 promise2 決定 promise1 的結果如果promise2 有 then 方 var promise2Then = promise2.then,我們這樣promise2Then.bind(promise1,resolve,reject)
promise 的狀態和終值都是通過 當前 promise 的 resolve 和 reject 來改變的,所以只需要將 promise1 的這兩個函數通過promise2 的 then 方法添加的 promise2 的執行隊列中就可以達到想要的效果
Promise 解析過程對于 promise.then(fn),then 方法返回 promise1,fn 方法返回 x,fn 接收到的參數為 y,這時需要對 x 和 y 分別運行Promise解析過程
x: [[Resolve]](promise1, x)
y: [[Resolve]](promise1, y)
x 的解析過程處理的是 回掉中返回 promise 的情況
y 的解析過程處理的是 向當前 promise 傳遞處理結果的那個 promise 的終值是 promise 的情況
由此可見 promise 的解析過程是遞歸的,遞歸的終點是 x,y 不是promise,在是對象或者函數的情形下不具備 then 方法
代碼結構(function(window) { var PENDING = 0; //PENDING 狀態 var RESOLVED = 1; //RESOLVED 狀態 var REJECTED = 2; //REJECTED 狀態 function IPromise(fn) { if (!(this instanceof IPromise)) return new IPromise(fn); //確保 通過 new IPromise() 和 IPromise() 都能正確創建對象 var state = PENDING; //promise 狀態 var value = null; //終值 var callback = []; //回掉函數隊列,在一種是兩個隊列,這里是一個,所以存放的是對象 function reject(reason) {} //reject 方法 function resolve(result) {} //和(一)中的對比 這里多了 執行 Promise 解析過程 的功能 function handle(handler) {} //添加或執行隊 callback 中的調用 /** *@param onFulfilled 通過 then 方法添加的 onFulfilled *@param onRejected 通過 then 方法添加的 onRejected * *@func 包裝用戶添加的回調 *因為這里只有一個回掉隊列所以需要用 candy(糖果) 包裝成{onFulfilled:onFulfilled,onRejected:onRejected} * *@func 延遲調用handle *在 Promise 規范解讀及實現細節 (一) 中說 Promise(瀏覽器實現) 會被加入到microtask,由于瀏覽器沒有提供除Promise *之外microtask的接口,所以 我們要用 setTimeout 來延遲調用并添加到 macrotask * */ function candy(onFulfilled, onRejected) {} function getThen(value) {} //判斷 value 是否有 then 方法如果有則獲取 this.then = function(onFulfilled, onRejected) {} //暴露的 then 方法 doResolve(fn, resolve, reject); //執行 fn window.IPromise = IPromise; //將 IPromise 添加到瀏覽器的 window 上 } /** *Promise 解析過程 */ function doResolve(fn, resolvePromise, rejectPromise) {} //靜態私有方法,解析并執行promise(解析并執行fn和promise的處理結果) })(window);
以上通過 js 自執行函數將變量和函數限制在了作用域中,在全局的 window 上只暴露一個構造函數 IPromise 保證了全局不被污染
具體代碼及解釋(請在瀏覽器中運行)/** *@author ivenj *@date 2016-12-06 *@version 1.0 */ (function(window) { var PENDING = 0; var RESOLVED = 1; var REJECTED = 2; function IPromise(fn) { if (!(this instanceof IPromise)) return new IPromise(fn); var state = PENDING; var value = null; var callback = []; function reject(reason) { state = REJECTED; value = reason; callback.forEach(handle); callback = null; } /** * 這里新增的內容是 滿足Promise解析過程時 resolve和doResolve相互調用形成遞歸 **/ function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject); //aa return; //這里如果 resule 是有 then 方法則執行 doResolve 并返回不執行后續代碼 } //只有 result 不滿足 解析過程時執行,即遞歸終點 state = RESOLVED; value = result; callback.forEach(handle); callback = null; } catch (e) { reject(e); } } function handle(handler) { if (state === PENDING) { callback.push(handler); } else { if (state === RESOLVED && typeof handler.onFulfilled === "function") { handler.onFulfilled(value); } if (state === REJECTED && typeof handler.onRejected === "function") { handler.onRejected(value); } } } function candy(onFulfilled, onRejected) { setTimeout(function() { handle({ onFulfilled: onFulfilled, onRejected: onRejected }); }, 0); } function getThen(value) { var type = typeof value; if (value && (type === "object" || type === "function")) { try{ var then = value.then; }catch(e){ reject(e); } if (typeof then === "function") { return then; } } return null; } this.then = function(onFulfilled, onRejected) { var self = this; return new IPromise(function(resolve, reject) { candy(function(x) { if (typeof onFulfilled === "function") { try { resolve(onFulfilled(x)); //cc 運行 [[Resolve]](promise, x) } catch (e) { reject(e); } } else { resolve(x); } }, function(error) { if (typeof onRejected === "function") { try { resolve(onRejected(error)); } catch (e) { reject(e); } } else { reject(error); } }); }); }; doResolve(fn, resolve, reject); } /** *Promise 解析過程 */ function doResolve(fn, resolvePromise, rejectPromise) { var done = false; //用于保證只調用一次 try { fn(function(y) { if (done) return; done = true; resolvePromise(y); //bb 如果 resolvePromise 以值 y 為參數被調用,則運行 [[Resolve]](promise, y) }, function(reason) { if (done) return; done = true; rejectPromise(reason); }); } catch (e) { if (done) return; done = true; rejectPromise(e); } } window.IPromise = IPromise; })(window);
這里是用于測試的代碼 讀者將以上代碼和以下代碼粘貼到瀏覽器去運行 一秒后會打印 {url: "http://ivenj_", value: 10}
function post(url, callback) { setTimeout(function() { var data = { //模擬異步處理結果 url:url, value:10 }; callback(data); }, 1000); } var promise = IPromise(function(resolve, reject){ post("http://ivenj_", function(data){ resolve(data); }); }); promise.then(function(data){ console.log(data); });
Promise 實現最核心的內容是代碼中的 //aa //bb //cc 讀者需要著重體會這三處
Promise 到此已經結束
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88328.html
摘要:宏任務和微任務這兩個是指兩個隊列,腳本整體代碼的回調及渲染都會被加入到隊列中回調瀏覽器實現回調都會被加入到隊列。 1. macrotask (宏任務)和 microtask (微任務) 這兩個是指兩個隊列,腳本整體代碼、setTimeout、setInterval、setImmediate、I/O、的回調及UI渲染都會被加入到 macrotask 隊列中, process.nextTi...
摘要:前兩個函數對應的兩種狀態和的回調函數。返回值是和對應的方法,但是會在下一事件循環返回。此外,在規范中,由方法生成的對象是已執行還是已拒絕,取決于由方法調用的那個回調是返回值還是拋出錯誤。但是對于其工作原理卻有些懵懂和好奇。 原文: https://blog.coding.net/blog/how-do-promises-work Javascript 采用回調函數(callback)來...
摘要:英文官方文檔原文前言寫本文的目的,是為了更好的理解,通過解讀翻譯原文,逐行解析原文通過代碼一行一行實現。英中原因是一個值結果表明被拒絕的原因。英中在法律允許的范圍內,組織已放棄所有版權及規范的相關或相鄰權利。 英文官方文檔原文:https://promisesaplus.com/ 前言 寫本文的目的,是為了更好的理解promise,通過解讀翻譯原文,逐行解析原文通過代碼一行一行實現。...
摘要:生成文件,是模塊構建的終點,包括輸出文件與輸出路徑。這里配置了處理各模塊的,包括預處理,編譯,圖片處理。各插件對象,在的事件流中執行對應的方法。修改改成引入模塊在目錄下執行, webpack原理解讀 本文抄自《深入淺出webpack》,建議想學習原理的手打一遍,操作一遍,給別人講一遍,然后就會了在閱讀前希望您已有webpack相關的實踐經驗,不然讀了也讀不懂 本文閱讀需要幾分鐘,理解需...
摘要:我們都知道,方法中有和兩個回調函數,所以我們要處理一下這兩個回調函數。我們實現了異步調用,在方法中返回或者值,實現了方法中可以沒有回調函數也能把執行結果傳入下一次的方法中。 Hello everybody。我又來啦,還記得我們上一張實現的內容嗎? showImg(https://segmentfault.com/img/bV6UaU?w=102&h=95); 上一張我們實現了一個簡單的...
閱讀 1206·2021-11-24 11:16
閱讀 3435·2021-11-15 11:38
閱讀 1929·2021-10-20 13:47
閱讀 552·2021-09-29 09:35
閱讀 2199·2021-09-22 15:17
閱讀 1016·2021-09-07 09:59
閱讀 3387·2019-08-30 13:21
閱讀 2910·2019-08-30 12:47