Promise對象用於異步計算。一個Promise對象表明着一個還未完成,但預期未來會完成的操做。git
Note:es6
Promise原理分析二github
Promise對象有如下幾種狀態:segmentfault
pending: 初始狀態, 既不是 fulfilled 也不是 rejected.設計模式
fulfilled: 成功的操做.promise
rejected: 失敗的操做.異步
pending狀態的Promise對象既可轉換爲帶着一個成功值的fulfilled狀態,也可變爲帶着一個失敗信息的 rejected狀態。當狀態發生轉換時,Promise.then綁定的方法就會被調用。(當綁定方法時,若是 Promise對象已經處於fulfilled或rejected狀態,那麼相應的方法將會被馬上調用,因此在異步操做的完成狀況和它的綁定方法之間不存在競爭條件。)函數
由於Promise.prototype.then和Promise.prototype.catch方法返回Promises對象, 因此它們能夠被鏈式調用。ui
語法this
new Promise(executor); new Promise(function(resolve, reject) { ... });
參數
name | desc |
---|---|
executor | 帶有resolve、reject兩個參數的函數對象。第一個參數用在處理執行成功的場景,第二個參數則用在處理執行失敗的場景。一旦咱們的操做完成便可調用這些函數。 |
構造函數主要完成狀態的初始化,並提供resolve
和reject
兩個方法給建立者以轉變狀態。
const utils = require('./utils'); const isFunction = utils.isFunction; const STATUS = { PENDING: 'pending', FULFILLED: 'fulfilled', REJECTED: 'rejected' }; const SYMBOL_STATUS = Symbol('status'); const SYMBOL_DATA = Symbol('data'); const SYMBOL_FULFILLED_CALLBACK = Symbol('fulfilledCallback'); const SYMBOL_REJECTED_CALLBACK = Symbol('rejectedCallback'); class Promise { constructor(executor) { if (!isFunction(executor)) { throw Error(`Promise executor ${executor} is not a function`); } const self = this; // 初始狀態爲pending const status = self[SYMBOL_STATUS] = STATUS.PENDING; // 使用symbol實現私有化 self[SYMBOL_FULFILLED_CALLBACK] = undefined; self[SYMBOL_REJECTED_CALLBACK] = undefined; self[SYMBOL_DATA] = undefined; function resovle(value) { // todo } function reject(reason) { // todo } // 執行executor函數,若出現異常則調用reject方法,將狀態變爲rejected,同時調用回調函數 try { executor(resovle, reject); } catch (err) { reject(err); } } }
上面代碼中完成了構造函數的雛形,而resolve
和reject
兩個函數的職責爲狀態轉變和回調函數的調用:
resolve,接受一個成功值,傳遞給綁定的fulfilled回調函數中。主要工做是將當前狀態變爲fulfilled
狀態,同時調用綁定的fulfilled回調函數:
function resovle(value) { const fulfilledCallback = self[SYMBOL_FULFILLED_CALLBACK]; if (status === STATUS.PENDING) { self[SYMBOL_STATUS] = STATUS.FULFILLED; // 狀態轉換 self[SYMBOL_DATA] = value; // 保存成功值 if (isFunction(fulfilledCallback)) { setTimeout(() => { // 不阻塞主流程,在下一個事件輪詢中再調用fulfilled回調函數 fulfilledCallback(value); }); } } }
reject,接受一個失敗信息,傳遞給綁定的rejected回調函數中。主要工做是將當前狀態變爲rejected
狀態,同時調用綁定的rejected回調函數:
function reject(reason) { const rejectedCallback = self[SYMBOL_REJECTED_CALLBACK]; if (status === STATUS.PENDING) { self[SYMBOL_STATUS] = STATUS.REJECTED; // 狀態轉換 self[SYMBOL_DATA] = reason; // 保存成功值 if (isFunction(rejectedCallback)) { setTimeout(() => { // 不阻塞主流程,在下一個事件輪詢中再調用rejected回調函數 rejectedCallback(reason); }); } } }
fulfilled`和rejected回調函數是經過Promise.prototype.then和Promise.prototype.catch註冊的。
then方法返回一個Promise。它有兩個參數,分別爲Promise在成功和失敗狀況下的回調函數。
語法
p.then(onFulfilled, onRejected); p.then(function(value) { // todo }, function(reason) { // todo });
參數
name | desc |
---|---|
onFulfilled | 一個函數,當Promise的狀態爲fulfilled時調用。該函數有一個參數,爲成功的返回值。 |
onRejected | 一個函數,當Promise的狀態爲rejected時調用。該函數有一個參數,爲失敗的緣由。 |
根據當前狀態對回調函數進行處理,同時返回一個新的Promise對象,以便鏈式調用。
then(onFulfilled, onRejected) { const self = this; const status = self[SYMBOL_STATUS]; const data = self[SYMBOL_DATA]; const resolveValue = self[SYMBOL_RESOLVE_VALUE]; // 若是onFulfilled不是函數,回調函數僅返回成功值 const fulfilledCallback = isFunction(onFulfilled) ? onFulfilled : function returnFunc(value) { return value; }; // 若是onRejected不是函數,回調函數僅返回失敗信息 const rejectedCallback = isFunction(onRejected) ? onRejected : function throwFunc(reason) { throw reason; }; // 當前狀態爲pending if (status === STATUS.PENDING) { // 返回一個新的Promise對象,能夠被鏈式調用 return new Promise((resolve, reject) => { // 將fulfilled回調函數註冊到當前Promise對象中(非新Promise對象) self[SYMBOL_FULFILLED_CALLBACK] = value => { // 根據回調函數的執行狀況,經過傳遞的新Promise對象的resolve和reject方法對其狀態進行轉變 try { const newValue = fulfilledCallback(value); // 解析成功值 resolveValue(newValue, resolve, reject); } catch (err) { reject(err); } }; // 同上 self[SYMBOL_REJECTED_CALLBACK] = reason => { try { const newReason = rejectedCallback(reason); resolveValue(newReason, resolve, reject); } catch (err) { reject(err); } }; }); } // 當前狀態爲fulfilled if (status === STATUS.FULFILLED) { // 返回一個新的Promise對象,能夠被鏈式調用 return new Promise((resolve, reject) => { // 在下一個事件輪詢中當即調用fulfilled回調函數,根據執行狀況決定新Promise對象的狀態轉變 setTimeout(() => { try { const newValue = fulfilledCallback(data); resolveValue(newValue, resolve, reject); } catch (err) { reject(err); } }); }); } // 當前狀態爲rejected if (status === STATUS.REJECTED) { // 返回一個新的Promise對象,能夠被鏈式調用 return new Promise((resolve, reject) => { // 在下一個事件輪詢中當即調用rejected回調函數,根據執行狀況決定新Promise對象的狀態轉變 setTimeout(() => { try { const newReason = rejectedCallback(data); resolveValue(newReason, resolve, reject); } catch (err) { reject(err); } }); }); } } // 解析傳遞值函數 [SYMBOL_RESOLVE_VALUE](value, resolve, reject) { // 若傳遞值爲Promise對象,將新Promise對象的resolve和reject傳遞給Promise傳遞值以觸發狀態的轉換 if (value instanceof Promise) { value.then(resolve, reject); return; } // 若傳遞值不是Promise對象,傳遞給resolve方法 resolve(value); }
根據當前Promise對象的狀態,對回調函數進行註冊或當即執行,同時返回一個新的Promise對象。
pending,註冊回調函數到當前的Promise對象中
fulfilled或rejected,當即執行回調函數
catch方法只處理Promise被拒絕的狀況,並返回一個Promise。該方法的行爲和調用Promise.prototype.then(undefined, onRejected)相同。
語法
p.catch(onRejected); p.catch(function(reason) { // todo });
參數
name | desc |
---|---|
onRejected | 當Promise被拒絕時調用的函數。該函數調用時會傳入一個參數:失敗緣由。 |
catch方法是對then方法的包裝,僅傳遞onRejected失敗回調函數。
catch(onRejected) { return this.then(null, onRejected); }
如今回顧下Promise的實現過程,其主要使用了設計模式中的觀察者模式:
經過Promise.prototype.then和Promise.prototype.catch方法將觀察者方法註冊到被觀察者Promise對象中,同時返回一個新的Promise對象,以即可以鏈式調用。
被觀察者管理內部pending、fulfilled和rejected的狀態轉變,同時經過構造函數中傳遞的resolve和reject方法以主動觸發狀態轉變和通知觀察者。
MDN
ruanyifeng
百度百科