摘要:源碼學習本篇為上一篇源碼學習的補充,主要是來介紹和方法。那個率先改變的實例的返回值,就傳遞給的回調函數?;窘榻B可見阮一峰老師的書籍。的狀態由決定,分成兩種情況。只有的狀態都變成,的狀態才會變成,此時的返回值組成一個數組,傳遞給的回調函數。
Promise源碼學習(2)
本篇為上一篇源碼學習(1)的補充,主要是來介紹Promise.all()和Promise.race()方法。
閑話少敘,進入正題
首先來簡單介紹一下功能吧,詳細比如可見阮一峰老師的ES6書籍。
Promise.race方法是將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。
接下來貼源代碼
export default function race (entries) { /*jshint validthis:true */ let Constructor = this; if (!isArray(entries)) { return new Constructor((_resolve, reject) => reject(new TypeError("You must pass an array to race."))); } else { return new Constructor((resolve, reject) => {//new 執行一次 let length = entries.length; for (let i = 0; i < length; i++) {//執行每一個傳入的entry 但只有最快的一個能resolve或reject改變返回的promise的狀態 Constructor.resolve(entries[i]).then(resolve, reject); } }); } } //isArray定義: if (Array.isArray) { _isArray = Array.isArray; } else { _isArray = x => Object.prototype.toString.call(x) === "[object Array]"; }
如果傳入的參數不是數據直接reject。
如果是數組,則依次resolve傳入的thenable對象并在then中注冊回調,設Promise.race()返回的新Promise的對象為p的話,最快執行完成的entry進入then回調,執行resolve或reject,以此來改變新對象p的狀態。之后的entry完成在此執行resolve或reject均無效,因為Promise狀態一旦確定無法改變,詳見上篇關于fulfill()和reject()的注釋和分析。
基本介紹可見阮一峰老師的ES6書籍。
Promise.all方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.all([p1, p2, p3]);
p的狀態由p1、p2、p3決定,分成兩種情況。
(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
源碼:
export default function all(entries) { return new Enumerator(this, entries).promise;//這里返回了一個新對象Promise }
這里注意返回了一個新的Promise對象.
Enumerator源碼如下
export default class Enumerator { constructor (Constructor, input) { this._instanceConstructor = Constructor; //Promise.all([...])會返回一個新的promise this.promise = new Constructor(noop); if (!this.promise[PROMISE_ID]) { makePromise(this.promise); } if (isArray(input)) { this.length = input.length; this._remaining = input.length;//未完成的promise總數量 this._result = new Array(this.length);//每個promise結果 if (this.length === 0) { fulfill(this.promise, this._result); } else { this.length = this.length || 0; this._enumerate(input);//處理輸入的數組 if (this._remaining === 0) {//都執行完畢 fulfill(this.promise, this._result); } } } else { reject(this.promise, validationError());//傳入不是array, reject it } } _enumerate (input) { for (let i = 0; this._state === PENDING && i < input.length; i++) {//Enumerator _state?? TODO this._eachEntry(input[i], i); } } //處理所有的輸入 _eachEntry (entry, i) { let c = this._instanceConstructor;//Promise let {resolve} = c;//Promise.resolve if (resolve === originalResolve) { let then = getThen(entry);//獲取then方法 if (then === originalThen && entry._state !== PENDING) {//如果entry已完成或已拒絕 this._settledAt(entry._state, i, entry._result); } else if (typeof then !== "function") { this._remaining--;//不是thenable 直接完成該entry this._result[i] = entry; } else if (c === Promise) {//不是promise但是一個thenable let promise = new c(noop); handleMaybeThenable(promise, entry, then); this._willSettleAt(promise, i);//暫時狀態不確定,訂閱之 } else { this._willSettleAt(new c(resolve => resolve(entry)), i); } } else { this._willSettleAt(resolve(entry), i); } } _settledAt (state, i, value) { let {promise} = this; if (promise._state === PENDING) { this._remaining--;//該entry狀態已確定,待完成總數減一 if (state === REJECTED) { reject(promise, value);//如果傳入entry列表有一個rejected,立即設置promise結果rejected } else { this._result[i] = value; } } if (this._remaining === 0) {//全部處理完成fulfill fulfill(promise, this._result); } } _willSettleAt (promise, i) { let enumerator = this; //暫時狀態不定,訂閱之 subscribe( promise, undefined, value => enumerator._settledAt(FULFILLED, i, value),//回調,設置promise狀態 reason => enumerator._settledAt(REJECTED, i, reason) ); } };
代碼不是很多,在此就不逐個方法貼了。
首先看Constructor,細節不表,如果傳入了一個thenable數組會在_enumerate方法中通過_eachEntry挨個處理,細節見注釋。
總體思路就是對傳入列表的元素挨個處理,該resolve則resolve,同時通過_remaining 對未完成的entry進行計數。
若entry是pending狀態,則通過_willSettleAt來訂閱,有確定結果時進行 _settledAt;
若entry已完成,直接_settledAt確定結果;
當_remaining === 0;也就是列表所有entry均已有結果,設置Promise.all()返回的新Promise對象的狀態。
要注意,如果有一個entry被reject了,會直接設置 新Promise對象的狀態為rejected。
該圖對Promise的流程總結。
總的來說,Promise通過鏈式語法使得異步操作更加的直觀,避免了回調地獄的出現。使得代碼更加易讀可維護。
細節可見源碼上的注釋,全部代碼可見es6-promise學習筆記
明后兩天公司集體出游,沒有大多的時間來打磨,可是自己又定了一個每周一篇學習總結小文章的目標,所以擠些時間提前寫完這篇文章來完成目標吧。繼續加油吧!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94468.html
摘要:工作當中經常會用到,在此進行深入學習異步編程解決方案是異步編程的一種解決方案,比傳統的解決方案回調函數和事件更合理和更強大。所有源碼注釋見學習筆記 工作當中經常會用到Promise,在此進行深入學習 異步編程解決方案 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了...
摘要:源碼閱讀階段緊接上一篇這次我們開始我們最常用到的部分的源碼解析傳入參數為兩個函數和判斷調用者是否為對象跳轉到了一個叫做的函數里面新建一個對象傳入函數傳入給和一個新的對象返回新的對象在這里我們先看看在調用者不是對象時到底做了什么比想象的要簡單 源碼閱讀階段 緊接上一篇,這次我們開始Promise我們最常用到的then部分的源碼解析. then() //傳入參數為兩個函數,onFulfil...
摘要:源碼閱讀階段先理解根本吧想快點理解的話可以直接跳到下個標題這部分根據理解將持續修改空函數用于判斷傳入構造器的函數是否為空函數如果為空函數構造一個對象并初始化狀態為終值回調狀態和隊列記錄內部最后的一次錯誤空對象標識表示發生了錯誤暴露模塊接口為 源碼閱讀階段 先理解Promise根本吧,想快點理解的話可以直接跳到下個標題.這部分根據理解將持續修改. Promise(fn) function...
摘要:第三篇腳手架依賴的核心庫的源碼解析。該篇是這個系列文章的第三篇主要是對的源碼進行分析講解。的源碼十分簡單但實現的功能卻是十分的強大。源碼概括源碼主要包含了兩部分公共方法和私有方法。 react作為當前十分流行的前端框架,相信很多前端er都有蠢蠢欲動的學習它的想法。工欲善其事,必先利其器。這篇文章就簡單的給大家介紹一下如何我快速的搭建一個react前端開發環境。主要針對于react小白,...
摘要:下一篇大概就是源碼方面的學習筆記了龜速學習中這一次我是去看了下規范照例傳送門圖靈社區規范首先吧個人總結下該用的詞解決結婚拒絕婉拒終值值傳家寶拒因好人卡等等異常車禍理下概念我們的的就像是一場姻緣對吧解決呢就是結婚成功啦傳家寶也如愿的傳給下一代 下一篇大概就是源碼方面的學習筆記了...龜速學習中... 這一次我是去看了下Promises/A+規范照例傳送門:圖靈社區Promises/A+規...
閱讀 2007·2021-11-24 10:45
閱讀 1866·2021-10-09 09:43
閱讀 1303·2021-09-22 15:38
閱讀 1230·2021-08-18 10:19
閱讀 2850·2019-08-30 15:55
閱讀 3070·2019-08-30 12:45
閱讀 2975·2019-08-30 11:25
閱讀 365·2019-08-29 11:30