學習React有一段時間了,剛接觸不久對於React神奇的操做很好奇,火燒眉毛看了源碼看過幾遍源碼老是隻知其一;不知其二,最近有時間再次學習React的相關知識,好比setState
, componentDidMount
等,意識到了以前被忽略說起的知識點,那就是React內部的事務,我的以爲事務很重要,生命週期中的componentWillMount
,componentDidMount
, componentDidUpdate
以及在一些生命週期中進行setState出現的一些出乎本身認知的結果,都和事務有很大的關係。javascript
根據維基百科的解釋: 提供獨立可靠的恢復機制,保證出錯時數據的一致性,而且不一樣事務之間互相獨立。
事務通常在數據庫中使用的比較多,能保證出錯的時候進行rollbakc恢復。在React源碼中做者給出了事務的一張明細圖可以幫助較好的理解。React內部的事務分爲三個階段initialize, method以及close階段,會在開始和結束時候分別遍歷transactionWrapper內部的全部初始化方法和close方法。前端
React內部有個事務對象,可以適配不一樣類型的事務:java
Transaction.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, method, scope, a)
主要先介紹2種事務,分別對應虛擬生命週期事務,狀態更新時的事務react
初始化進行組件掛載的時候會進行批量更新,批量更新方法會將ReactDefaultBatchingStrategy對象中的isBatchingUpdates設置爲true,這也將致使後續加入的setState只會加入dirtyComponents
中,在最後事務close的時候進行狀態合併,這也解釋了爲什麼在componentDidMount中寫多個setState,最後輸出的狀態不是意料值。數據庫
var ReactDefaultBatchingStrategy = { isBatchingUpdates: false, /** * Call the provided function in a context within which calls to `setState` * and friends are batched such that components aren't updated unnecessarily. */ batchedUpdates: function (callback, a, b, c, d, e) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; ReactDefaultBatchingStrategy.isBatchingUpdates = true; // The code is written this way to avoid extra allocations if (alreadyBatchingUpdates) { return callback(a, b, c, d, e); } else { return transaction.perform(callback, null, a, b, c, d, e); } } };
// 將新的partialState加入到_pendingStateQueue之後的組件加到dirtyComponents function enqueueUpdate(component) { ensureInjected(); if (!batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component); return; } dirtyComponents.push(component); if (component._updateBatchNumber == null) { component._updateBatchNumber = updateBatchNumber + 1; } }
首先是初始化遍歷執行emptyFunction,而後執行內部的被包裝的方法,這裏是batchedMountComponentIntoNode
,顧名思義這個就是將虛擬DOM插入到真實節點下的方法,具體方法涉及到類別判斷來實例化不一樣類型的組件,遞歸插入等等不在本章的討論範圍,不過有一點須要注意的是在這個方法內部進行已新事物,我稱之爲生命週期事務
(ReactReconcileTransaction)。在最後close的階段調用flushBatchedUpdates
方法進行將至更新完成,以及會將isBatchingUpdates
設置爲flase,這兩個close前後順序有必定講究,這也致使在這個事件或者componentDidMount中isBatchingUpdates的值始終爲true,在最後結束纔會爲false。app
var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES]; var RESET_BATCHED_UPDATES = { initialize: emptyFunction, close: function () { ReactDefaultBatchingStrategy.isBatchingUpdates = false; } }; var FLUSH_BATCHED_UPDATES = { initialize: emptyFunction, close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates) };
而上述說到的flushBatchedUpdates方法內部再次調用了一個新事務框架
該事物我稱之爲更新事務,主要和setState有關,過程當中會調用runBatchedUpdates, 將callBack函數加入到隊列中,並將_pendingCallbacks的引用清空,關閉的時候的close方法主要是對dirtyComponents清空以及setState中回調函數的通知ide
var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING]; var NESTED_UPDATES = { initialize: function () { this.dirtyComponentsLength = dirtyComponents.length; }, close: function () { if (this.dirtyComponentsLength !== dirtyComponents.length) { dirtyComponents.splice(0, this.dirtyComponentsLength); flushBatchedUpdates(); } else { dirtyComponents.length = 0; } } }; var UPDATE_QUEUEING = { initialize: function () { this.callbackQueue.reset(); }, close: function () { this.callbackQueue.notifyAll(); } };
if (inst.componentDidMount) { if ("development" !== 'production') { transaction.getReactMountReady().enqueue(function () { measureLifeCyclePerf(function () { return inst.componentDidMount(); }, _this._debugID, 'componentDidMount'); }); } else { transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); } }
在這裏開啓了一個事務,componentDidMount被放入了callbacks隊列中,當生命週期結束的時候會遍歷事務中的close方法,其中就有notifyAll方法遍歷callbacks進行輸出,而這裏的callback方法即爲componentDidMount
或者componentDidUpdate
。函數
var TRANSACTION_WRAPPERS = [SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING]; var EVENT_SUPPRESSION = { initialize: function () { var currentlyEnabled = ReactBrowserEventEmitter.isEnabled(); ReactBrowserEventEmitter.setEnabled(false); return currentlyEnabled; }, // restores the previous value. close: function (previouslyEnabled) { ReactBrowserEventEmitter.setEnabled(previouslyEnabled); } }; /** * Provides a queue for collecting `componentDidMount` and * `componentDidUpdate` callbacks during the transaction. */ var ON_DOM_READY_QUEUEING = { /** * Initializes the internal `onDOMReady` queue. */ initialize: function () { this.reactMountReady.reset(); }, /** * After DOM is flushed, invoke all registered `onDOMReady` callbacks. */ close: function () { this.reactMountReady.notifyAll(); } }; if ("development" !== 'production') { TRANSACTION_WRAPPERS.push({ initialize: ReactInstrumentation.debugTool.onBeginFlush, close: ReactInstrumentation.debugTool.onEndFlush }); }
總之,React真的每次看都會爲內部的實現所驚歎,雖然是前端的一種框架,但仍是感受能學到不少思想和知識,寫的不對的地方還但願獲得大牛們的指正。學習