摘要:最后當?shù)姆祷刂禐闀r,也會執(zhí)行方法。遍歷傳入的數(shù)組,經過的源碼可以看到,如果是一個則戶直接將這個返回,最后數(shù)組中的哪個優(yōu)先回調即執(zhí)行。
前言
then/promise項目是基于Promises/A+標準實現(xiàn)的Promise庫,從這個項目當中,我們來看Promise的原理是什么,它是如何做到的,從而更加熟悉Promise
分析從index.js當中知道,它是先引出了./core.js,隨后各自執(zhí)行了其他文件的代碼,通過requeire的方法。
我們首先先想一下最基礎的promise用法
new Promise((resolve, reject) => { resolve(4); }).then(res => { console.log(res); // export 4 });Promise中的標準
標準中規(guī)定:
Promise對象初始狀態(tài)為 Pending,在被 resolve 或 reject 時,狀態(tài)變?yōu)?Fulfilled 或 Rejected
resolve接收成功的數(shù)據(jù),reject接收失敗或錯誤的數(shù)據(jù)
Promise對象必須有一個 then 方法,且只接受兩個可函數(shù)參數(shù) onFulfilled、onRejected
index.js
"use strict"; module.exports = require("./core.js"); require("./done.js"); require("./finally.js"); require("./es6-extensions.js"); require("./node-extensions.js"); require("./synchronous.js");
我們先看src/core.js
function Promise(fn) { // 判斷 this一定得是object不然就會報錯,這個方法一定得要new出來 if (typeof this !== "object") { throw new TypeError("Promises must be constructed via new"); } // 判斷fn 一定得是一個函數(shù) if (typeof fn !== "function") { throw new TypeError("Promise constructor"s argument is not a function"); } this._deferredState = 0; this._state = 0; this._value = null; this._deferreds = null; if (fn === noop) return; // 最終doResolve很關鍵 doResolve(fn, this); }
Promise是一個構造方法,開始時,它進行了校驗,確保了fn是一個函數(shù),隨后對一些變量進行了初始化,最后執(zhí)行了doResolve()
我們接著看doResolve這個方法。
/** * Take a potentially misbehaving resolver function and make sure * onFulfilled and onRejected are only called once. * * Makes no guarantees about asynchrony. */ // // 確保`onFulfilled`和`onRejected`方法只調用一次 // 不保證異步 function doResolve(fn, promise) { var done = false; var res = tryCallTwo(fn, function (value) { // 如果done 為true 則return if (done) return; done = true; // 回調執(zhí)行 resolve() resolve(promise, value); }, function (reason) { // 如果done 為true 則return if (done) return; done = true; reject(promise, reason); }); // res為truCallTwo()的返回值 // 如果done沒有完成 并且 res 是 `IS_ERROR`的情況下 // 也會執(zhí)行reject(),同時讓done完成 if (!done && res === IS_ERROR) { done = true; reject(promise, LAST_ERROR); } }
doResolve最關鍵的是執(zhí)行了tryCallTwo方法,這個方法的第二,第三個參數(shù)都是回調,當執(zhí)行回調后,done為true,同時各自會執(zhí)行resolve()或者reject()方法。最后當tryCallTwo的返回值為IS_ERROR時,也會執(zhí)行reject()方法。
我們先來看一下tryCallTwo方法
function tryCallTwo(fn, a, b) { try { fn(a, b); } catch (ex) { LAST_ERROR = ex; return IS_ERROR; } }
fn實際就是Promise初始化時的匿名函數(shù)(resolve, reject) => {},a,b則代表的是resolve()和reject()方法,當我們正常執(zhí)行完promise函數(shù)時,則執(zhí)行的是resolve則在doResolve中,我們當時執(zhí)行的第二個參數(shù)被回調,如果報錯,reject()被執(zhí)行,則第二個參數(shù)被回調。最后捕獲了異常,當發(fā)生了報錯時,會return IS_ERROR,非報錯時會return undinfed
再回到剛才的doResolve方法,當執(zhí)行了第二個參數(shù)的回調之后,會執(zhí)行resolve方法
function resolve(self, newValue) { // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure // 不能吃傳遞自己 if (newValue === self) { // 報錯 return reject( self, new TypeError("A promise cannot be resolved with itself.") ); } // promise作為參數(shù) if ( newValue && (typeof newValue === "object" || typeof newValue === "function") ) { // 獲取它的promise方法 讀取newValue.then var then = getThen(newValue); if (then === IS_ERROR) { // 如果then IS_ERROR return reject(self, LAST_ERROR); } if ( // 如果then是self的then // 并且Promise then === self.then && // newValue 屬于Promise newValue instanceof Promise ) { // _state為3 // 一般then之后走這里 // 執(zhí)行then(newValue)返回了promise self._state = 3; // selft.value為newValue self._value = newValue; // 當state為3時執(zhí)行 finale finale(self); return; } else if (typeof then === "function") { doResolve(then.bind(newValue), self); return; } } self._state = 1; self._value = newValue; finale(self); }
在沒有鏈式調用then的情況下(也就是只要一個then)的情況下,會將內部狀態(tài)_state設置成3,將傳入值賦給內部變量_value最后會執(zhí)行final()方法,不然則會使用doResolve來調用then
我們再來看下reject
function reject(self, newValue) { // _state = 2為reject self._state = 2; self._value = newValue; if (Promise._onReject) { Promise._onReject(self, newValue); } finale(self); }
在reject當中我們的_state變更為了2,同樣最后finale被調用。
我們來看下finale函數(shù)
// 執(zhí)行自己的deferreds function finale(self) { if (self._deferredState === 1) { handle(self, self._deferreds); self._deferreds = null; } if (self._deferredState === 2) { for (var i = 0; i < self._deferreds.length; i++) { // 遍歷handle handle(self, self._deferreds[i]); } // 將deferred 置空 self._deferreds = null; } }
在該方法當中根據(jù)不同的_deferredState,會執(zhí)行不同的handle方法。
我們再來看handle方法
function handle(self, deferred) { while (self._state === 3) { self = self._value; } // 如果有onHandle方法 則執(zhí)行該方法 if (Promise._onHandle) { Promise._onHandle(self); } // (初始 _state 為0) if (self._state === 0) { // (初始 _deferredState 為0) if (self._deferredState === 0) { self._deferredState = 1; self._deferreds = deferred; return; } // 如果 _deferredState是1 則__deferreds是一個數(shù)組 if (self._deferredState === 1) { self._deferredState = 2; self._deferreds = [self._deferreds, deferred]; return; } // 當走到這里 _deferredState應該是2 將deferred // 插入到數(shù)組當中 self._deferreds.push(deferred); return; } handleResolved(self, deferred); }
這里比較關鍵的應該就是通過deferredState不同的狀態(tài),將deferred放入deferreds當中。另外當我們的_state不為0時,最終會執(zhí)行handleResolved。
繼續(xù)看handleResolve()方法
function handleResolved(self, deferred) { asap(function() { // _state為1時,cb = onFulfilled 否則 cb = onRejected var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; if (cb === null) { if (self._state === 1) { resolve(deferred.promise, self._value); } else { reject(deferred.promise, self._value); } return; } var ret = tryCallOne(cb, self._value); if (ret === IS_ERROR) { reject(deferred.promise, LAST_ERROR); } else { resolve(deferred.promise, ret); } }); }.then((res) => { }).catch((error) => { })
在這個方法當中,會根據(jù)我們任務(_state)的不同狀態(tài),來執(zhí)行onFulfilled或者onRejected方法。當此方法調用時,也就是我們一個簡單的Promise的結束。
回到剛才說的Promise構造方法結束的時候
設置了Promise函數(shù)的一些變量
Promise._onHandle = null; Promise._onReject = null; Promise._noop = noop;
隨后在Promise的原型上設置了then方法。
Promise.prototype.then = function(onFulfilled, onRejected) { // 首先看這是誰構造的 如果不是promise // 則return 執(zhí)行safeThen if (this.constructor !== Promise) { return safeThen(this, onFulfilled, onRejected); } // 如果是則初始化一個Promise 但是參數(shù) noop 為空對象 {} var res = new Promise(noop); // 隨后執(zhí)行handle方法 handle(this, new Handler(onFulfilled, onRejected, res)); return res; };
在then這個方法中首先判斷了它是否由Promise構造的,如果不是,則返回并執(zhí)行safeThen,不然則執(zhí)行Promise構造一個res對象,然后執(zhí)行handle方法,最后將promise變量res返回。handle方法之前有提過,在這里,當初始化時_state和_deferred的轉改都為0,因此它會將defrred保存到promise當中。
先看一下上面說的safeThen方法
function safeThen(self, onFulfilled, onRejected) { return new self.constructor(function (resolve, reject) { var res = new Promise(noop); res.then(resolve, reject); handle(self, new Handler(onFulfilled, onRejected, res)); }); }流程
需要有一個Promise的構造方法,這個構造方法最終會執(zhí)行它的參數(shù)(resolve, reject) => {},聲明的then方法會通過handle()方法將onFulfilled和onRejected方法保存起來。當在外部調用resolve或者onRejected時,最終也會執(zhí)行handle但是它,會最后根據(jù)狀態(tài)來執(zhí)行onFulfilled或者onRejected。從而到我們的then回調中。
Promise的擴展 done對done的擴展在src/done.js當中
"use strict"; var Promise = require("./core.js"); module.exports = Promise; Promise.prototype.done = function (onFulfilled, onRejected) { var self = arguments.length ? this.then.apply(this, arguments) : this; self.then(null, function (err) { setTimeout(function () { throw err; }, 0); }); };
內部執(zhí)行了then()
finally對finally的擴展在src/finally.js當中
在Promise的標準當中,本身是沒有finally方法的,但是在ES2018的標準里有,finally的實現(xiàn)如下
"use strict"; var Promise = require("./core.js"); module.exports = Promise; Promise.prototype.finally = function (callback) { return this.then(function (value) { return Promise.resolve(callback()).then(function () { return value; }); }, function (err) { return Promise.resolve(callback()).then(function () { throw err; }); }); };
Promise的onFulfilled和onRejected 不管回調的哪個,最終都會觸發(fā)callback 回調。還要注意的一點是finally的返回也是一個Promise。
es6-extensions.js在es6-extensions.js文件當中包含了ES6的一些擴展。
Promise.resolvefunction valuePromise(value) { var p = new Promise(Promise._noop); // 將_state賦值為 非0 // _value進行保存 p._state = 1; p._value = value; // 這樣做的目的是省略的一些前面的邏輯 return p; } Promise.resolve = function (value) { if (value instanceof Promise) return value; if (value === null) return NULL; if (value === undefined) return UNDEFINED; if (value === true) return TRUE; if (value === false) return FALSE; if (value === 0) return ZERO; if (value === "") return EMPTYSTRING; // value return new Promise if (typeof value === "object" || typeof value === "function") { try { var then = value.then; if (typeof then === "function") { // 返回 返回了一個新的Promise對象 return new Promise(then.bind(value)); } } catch (ex) { // 如果報錯 則返回一個就只 return new Promise(function (resolve, reject) { reject(ex); }); } } return valuePromise(value); };Promise.reject
Promise.reject = function (value) { return new Promise(function (resolve, reject) { reject(value); }); };Promise.all
Promise.all = function (arr) { // 類似深拷貝了一份給了args var args = Array.prototype.slice.call(arr); return new Promise(function (resolve, reject) { // 判斷了all的promise數(shù)量 if (args.length === 0) return resolve([]); // remaining則是promise數(shù)組的長度 var remaining = args.length; // i為index val 為 promise function res(i, val) { if (val && (typeof val === "object" || typeof val === "function")) { if (val instanceof Promise && val.then === Promise.prototype.then) { while (val._state === 3) { val = val._value; } if (val._state === 1) return res(i, val._value); if (val._state === 2) reject(val._value); // val._state 為 0時 走這里 val.then(function (val) { res(i, val); }, reject); return; } else { var then = val.then; if (typeof then === "function") { var p = new Promise(then.bind(val)); p.then(function (val) { res(i, val); }, reject); return; } } } args[i] = val; // 當所有的promise執(zhí)行完 則是remaining為0 // 則執(zhí)行resolve(); if (--remaining === 0) { resolve(args); } } // 遍歷所有的promise for (var i = 0; i < args.length; i++) { res(i, args[i]); } }); };
Promise.all()返回的也是一個Promise函數(shù)。
內部有一個remaining變量每當執(zhí)行完一個promise函數(shù)后就會減一,當所有promise執(zhí)行完,會執(zhí)行自己的resolve。
Promise.race = function (values) { return new Promise(function (resolve, reject) { values.forEach(function(value){ Promise.resolve(value).then(resolve, reject); }); }); };
遍歷傳入的promise數(shù)組,經過Promise.resolve(value)的源碼可以看到,如果value是一個Promise則戶直接將這個value返回,最后數(shù)組中的promise哪個優(yōu)先回調即執(zhí)行。
Promise.property.catchcatch在標準當中也是沒有,雖然我們用的比較多
Promise.prototype["catch"] = function (onRejected) { return this.then(null, onRejected); };
catch的回調實際是then(null, onRejected)的回調。
廣而告之本文發(fā)布于薄荷前端周刊,歡迎Watch & Star ★,轉載請注明出處。
歡迎討論,點個贊再走吧 ????? ~文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/100298.html
摘要:返回的結果是一個對象,類似于表示本次后面執(zhí)行之后返回的結果。對象用于一個異步操作的最終完成或失敗及其結果值的表示簡單點說就是處理異步請求。源碼分析主要脈絡函數(shù)調用后,返回一個實例。參考鏈接解釋對象的用法的源碼及其用法 本文始發(fā)于我的個人博客,如需轉載請注明出處。為了更好的閱讀體驗,可以直接進去我的個人博客看。 前言 知識儲備 閱讀本文需要對Generator和Promise有一個基本的...
摘要:實例中構造函數(shù)的獲取每個實例中都包含一個的屬性,這個屬性指向的是實例的構造函數(shù),在獲取到這個構造函數(shù)后,就可以調用它的方法,然后就可以比較了。 焦慮和恐懼的區(qū)別是,恐懼是對世界上的存在的恐懼,而焦慮是在我面前的焦慮?!_特《存在與虛無》 本文為讀 lodash 源碼的第十九篇,后續(xù)文章會更新到這個倉庫中,歡迎 star:pocket-lodash gitbook也會同步倉庫的更新,...
摘要:目錄源碼之下無秘密做最好的源碼分析教程源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端 目錄 源碼之下無秘密 ── 做最好的 Netty 源碼分析教程 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NI...
摘要:為的項,取出來的分別為和,所以上的和方法,調用的是中的方法,實質是往各自的回調列表中添加回調函數(shù)。進度回調函數(shù)數(shù)組。參數(shù)為異步對象的索引值,參數(shù)為對應的上下文數(shù)組,即或,為對應的回調函數(shù)數(shù)組,即或。 Deferred 模塊也不是必備的模塊,但是 ajax 模塊中,要用到 promise 風格,必需引入 Deferred 模塊。Deferred 也用到了上一篇文章《讀Zepto源碼之C...
摘要:背景最近發(fā)現(xiàn)的回調方法,在連接創(chuàng)建成功和讀取數(shù)據(jù)后都會被回調。那我也嘗試著從源碼找到答案吧?;卣{流程分析的回調流程和流程沒有什么區(qū)別,可參考上文分析。但是在的方法中會調用這個是讀數(shù)據(jù)的關鍵讀數(shù)據(jù)分析讀數(shù)據(jù)分析 背景 最近發(fā)現(xiàn)ChannelOutboundHandlerAdapter的read()回調方法,在連接創(chuàng)建成功和讀取數(shù)據(jù)后都會被回調。因此就產生了疑問為什么建立連接和讀取數(shù)據(jù)后r...
摘要:第三篇腳手架依賴的核心庫的源碼解析。該篇是這個系列文章的第三篇主要是對的源碼進行分析講解。的源碼十分簡單但實現(xiàn)的功能卻是十分的強大。源碼概括源碼主要包含了兩部分公共方法和私有方法。 react作為當前十分流行的前端框架,相信很多前端er都有蠢蠢欲動的學習它的想法。工欲善其事,必先利其器。這篇文章就簡單的給大家介紹一下如何我快速的搭建一個react前端開發(fā)環(huán)境。主要針對于react小白,...
閱讀 2590·2021-10-19 11:41
閱讀 2425·2021-09-01 10:32
閱讀 3386·2019-08-29 15:21
閱讀 1766·2019-08-29 12:20
閱讀 1173·2019-08-29 12:13
閱讀 609·2019-08-26 12:24
閱讀 2527·2019-08-26 10:26
閱讀 843·2019-08-23 18:40