Promise 庫 lie.js 源碼解讀

這篇文章是通過lie.js的源碼一起去了解下如何實現(xiàn)Promise相關(guān)的規(guī)范。
首先是Promise的核心的構(gòu)造函數(shù)的實現(xiàn)。
function INTERNAL() {}var REJECTED = ['REJECTED'];var FULFILLED = ['FULFILLED'];var PENDING = ['PENDING'];var handlers = {}function Promise (resolver) {if (typeof resolver !== 'function') {throw new TypeError('resolver must be a function');}this.state = PENDING;this.queue = [];this.outcome = void 0;/* istanbul ignore else */if (!process.browser) {this.handled = UNHANDLED;}if (resolver !== INTERNAL) {safelyResolveThenable(this, resolver);}}
構(gòu)造函數(shù)內(nèi)部定義了幾個promise實例的屬性:
state:promise的狀態(tài)值.有3種:rejected,fulfilled,pending
queue:queue數(shù)組用以保存這個promise被resolve/rejected后需要異步執(zhí)行的回調(diào)
outcome:這個promise實例的值
對于promise,我們一般的用法是:
// 構(gòu)造函數(shù)當中接收2個參數(shù),resolve/reject,需要注意的是這2個參數(shù)是promise內(nèi)部定義的,用以改變這個promise的狀態(tài)和值const promise = new Promise((resolve, reject) => {// 同步或者異步的去resolve一個值resolve(1)})
給這個Promise構(gòu)造函數(shù)內(nèi)部傳入的resolver由內(nèi)部的方法safelyResolveThenable去執(zhí)行:
function safelyResolveThenable(self, thenable) {// Either fulfill, reject or reject with error// 標志位,初始態(tài)的promise僅僅只能被resolve/reject一次var called = false;function onError(value) {if (called) {return;}called = true;// reject這個promisehandlers.reject(self, value);}function onSuccess(value) {if (called) {return;}called = true;// resolve這個promisehandlers.resolve(self, value);}// 用一個函數(shù)將resolver執(zhí)行包裹一層function tryToUnwrap() {// 這個函數(shù)即由調(diào)用方傳入的thenable(onSuccess, onError);}// 用以捕獲resolver在執(zhí)行過程可能拋出的錯誤var result = tryCatch(tryToUnwrap);if (result.status === 'error') {onError(result.value);}}function tryCatch(func, value) {var out = {};try {out.value = func(value);out.status = 'success';} catch (e) {out.status = 'error';out.value = e;}return out;}
在safelyResolveThenable方法中設定了一個called標志位,這是因為一旦一個promise的狀態(tài)發(fā)生了改變,那么之后的狀態(tài)不能再次被改變,舉例:
new Promise((resolve, reject) => {// 一旦狀態(tài)發(fā)生改變,后面的reject/resolve方法不能起作用resolve(1)reject(new Error('error'))resolve(2)})
如果給Promise構(gòu)造函數(shù)傳入callback在執(zhí)行過程中沒有報錯,且被resolve的話,那么這個時候即調(diào)用的onSuccess方法,這個方法內(nèi)部調(diào)用了handlers.resolve方法。
接下來我們看下這個方法的定義:
handlers.resolve = function (self, value) {var result = tryCatch(getThen, value);if (result.status === 'error') {return handlers.reject(self, result.value);}// 判斷這個value是否是個thenable對象var thenable = result.value;if (thenable) {safelyResolveThenable(self, thenable);} else {// 將這個promise的state從 pending -> fulfilledself.state = FULFILLED;// 更改這個promise對應的值self.outcome = value;var i = -1;var len = self.queue.length;// 依次執(zhí)行這個promise的queue隊列里面每一項queueItem的callFulfilled方法while (++i < len) {self.queue[i].callFulfilled(value);}}// 返回這個promise對象return self;}
再回到我們上面舉的這個例子:
const promise = new Promise(resolve => {resolve(1)})
在這個例子當中,是同步去resolve這個promise,那么返回的這個promise實例的狀態(tài)便為fulfilled,同時outcome的值也被設為1。
將這個例子拓展一下:
const promise = new Promise(resolve => {resolve(1)})promise.then(function onFullfilled (value) {console.log(value)})
Promise.prototype.then = function (onFulfilled, onRejected) {if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||typeof onRejected !== 'function' && this.state === REJECTED) {return this;}// 創(chuàng)建一個新的promisevar promise = new this.constructor(INTERNAL);/* istanbul ignore else */if (!process.browser) {if (this.handled === UNHANDLED) {this.handled = null;}}// new Promise在內(nèi)部resolve過程中如果是同步的if (this.state !== PENDING) {var resolver = this.state === FULFILLED ? onFulfilled : onRejected;unwrap(promise, resolver, this.outcome);} else { // 異步的resolve// this.queue保存了對于promisethis.queue.push(new QueueItem(promise, onFulfilled, onRejected));}return promise;};
function unwrap(promise, func, value) {// 異步執(zhí)行這個funcimmediate(function () {var returnValue;try {// 捕獲onFulfilled函數(shù)在執(zhí)行過程中的錯誤returnValue = func(value);} catch (e) {return handlers.reject(promise, e);}// 不能返回自身promiseif (returnValue === promise) {handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));} else {handlers.resolve(promise, returnValue);}});}
function QueueItem(promise, onFulfilled, onRejected) {// 首先保存這個promisethis.promise = promise;// 如果onFulfilled是一個函數(shù)if (typeof onFulfilled === 'function') {this.onFulfilled = onFulfilled;// 那么重新賦值callFulfilled函數(shù)this.callFulfilled = this.otherCallFulfilled;}if (typeof onRejected === 'function') {this.onRejected = onRejected;this.callRejected = this.otherCallRejected;}}// 如果onFulfilled是一個函數(shù),那么就會覆蓋callFulfilled方法// 如果onFulfilled不是一個函數(shù),那么就會直接調(diào)用handlers.resolve去遞歸處理promiseQueueItem.prototype.callFulfilled = function (value) {handlers.resolve(this.promise, value);};QueueItem.prototype.otherCallFulfilled = function (value) {unwrap(this.promise, this.onFulfilled, value);};QueueItem.prototype.callRejected = function (value) {handlers.reject(this.promise, value);};QueueItem.prototype.otherCallRejected = function (value) {unwrap(this.promise, this.onRejected, value);};
onFullfilled:上一個promise被resolve后需要調(diào)用的回調(diào)
onRejected:上一個promise被reject后需要調(diào)用的回調(diào)函數(shù)
接下來我們看下第二種情況是在什么樣的情況下去執(zhí)行的:
const promise = new Promise(resolve => {setTimeout(() => {resolve(1)}, 3000)})promise.then(data => console.log(data))
const promise = new Promise(resolve => {setTimeout(() => {resolve(2)}, 2000)})promise.then(3).then(console.log)
const promise = new Promise(resolve => {// 情況一:同步resolveresolve(1)// 情況二:異步resolvesetTimeout(() => {resolve(2)}, 1000)})promise.then(function onFullfilled() {// do somethingfoo()})bar()
const Promise = require('lie')const promise = new Promise(resolve => setTimeout(resolve, 3000))promise.then(() => 'a').then(() => 'b').then(() => {})
需要注意的是,在每個then方法內(nèi)部創(chuàng)建的新的promise對象的state為pending態(tài),outcome為null??梢詫⑸厦媸纠膒romise打印到控制臺,你會非常清晰的看到整個promise鏈的結(jié)構(gòu):
Promise {state: [ 'PENDING' ],queue:[ QueueItem {promise: {state: ['PENDING'],queue: [QueueItem {promise: {state: ['PENDING'],queue: [QueueItem {promise: {state: ['PENDING'],queue: [],outcome: undefined}}],outcome: undefined,handled: null},onFulfilled: [Function],callFulfilled: [Function]}],outcome: undefined,handled: null},onFulfilled: [Function],callFulfilled: [Function] } ],outcome: undefined,handled: null }
someRequest().then(res => {if (res.error === 0) {// do somethingreturn res} else {return Promise.reject(res)}}).then(val => {// do something}).catch(err => {// do something})

評論
圖片
表情
