mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Make React batching strategy injectable
This commit is contained in:
committed by
Paul O’Shannessy
parent
f88aa35187
commit
0db4077c3a
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @providesModule ReactDefaultBatchingStrategy
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var Transaction = require('Transaction');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var mixInto = require('mixInto');
|
||||
|
||||
var RESET_BATCHED_UPDATES = {
|
||||
initialize: emptyFunction,
|
||||
close: function() {
|
||||
ReactDefaultBatchingStrategy.isBatchingUpdates = false;
|
||||
}
|
||||
};
|
||||
|
||||
var FLUSH_BATCHED_UPDATES = {
|
||||
initialize: emptyFunction,
|
||||
close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
|
||||
};
|
||||
|
||||
var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
|
||||
|
||||
function ReactDefaultBatchingStrategyTransaction() {
|
||||
this.reinitializeTransaction();
|
||||
}
|
||||
|
||||
mixInto(ReactDefaultBatchingStrategyTransaction, Transaction.Mixin);
|
||||
mixInto(ReactDefaultBatchingStrategyTransaction, {
|
||||
getTransactionWrappers: function() {
|
||||
return TRANSACTION_WRAPPERS;
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
|
||||
|
||||
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
|
||||
|
||||
// The code is written this way to avoid extra allocations
|
||||
if (alreadyBatchingUpdates) {
|
||||
callback();
|
||||
} else {
|
||||
var transaction = new ReactDefaultBatchingStrategyTransaction();
|
||||
transaction.perform(callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ReactDefaultBatchingStrategy;
|
||||
@@ -40,6 +40,9 @@ var ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
var SimpleEventPlugin = require('SimpleEventPlugin');
|
||||
var MobileSafariClickEventPlugin = require('MobileSafariClickEventPlugin');
|
||||
|
||||
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
|
||||
function inject() {
|
||||
ReactEventEmitter.TopLevelCallbackCreator = ReactEventTopLevelCallback;
|
||||
/**
|
||||
@@ -73,6 +76,10 @@ function inject() {
|
||||
if (__DEV__) {
|
||||
ReactPerf.injection.injectMeasure(require('ReactDefaultPerf').measure);
|
||||
}
|
||||
|
||||
ReactUpdates.injection.injectBatchingStrategy(
|
||||
ReactDefaultBatchingStrategy
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
+63
-39
@@ -20,51 +20,54 @@
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var isBatchingUpdates = false;
|
||||
|
||||
var dirtyComponents = [];
|
||||
|
||||
/**
|
||||
* Call the provided function in a context within which calls to `setState` and
|
||||
* friends are batched such that components aren't updated unnecessarily.
|
||||
*/
|
||||
var batchingStrategy = null;
|
||||
|
||||
function ensureBatchingStrategy() {
|
||||
invariant(batchingStrategy, 'ReactUpdates: must inject a batching strategy');
|
||||
}
|
||||
|
||||
function batchedUpdates(callback) {
|
||||
if (isBatchingUpdates) {
|
||||
// We're already executing in an environment where updates will be batched,
|
||||
// so this is a no-op.
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
ensureBatchingStrategy();
|
||||
batchingStrategy.batchedUpdates(callback);
|
||||
}
|
||||
|
||||
isBatchingUpdates = true;
|
||||
|
||||
try {
|
||||
callback();
|
||||
// TODO: Sort components by depth such that parent components update first
|
||||
for (var i = 0; i < dirtyComponents.length; i++) {
|
||||
// If a component is unmounted before pending changes apply, ignore them
|
||||
// TODO: Queue unmounts in the same list to avoid this happening at all
|
||||
var component = dirtyComponents[i];
|
||||
if (component.isMounted()) {
|
||||
// If performUpdateIfNecessary happens to enqueue any new updates, we
|
||||
// shouldn't execute the callbacks until the next render happens, so
|
||||
// stash the callbacks first
|
||||
var callbacks = component._pendingCallbacks;
|
||||
component._pendingCallbacks = null;
|
||||
component.performUpdateIfNecessary();
|
||||
if (callbacks) {
|
||||
for (var j = 0; j < callbacks.length; j++) {
|
||||
callbacks[j].call(component);
|
||||
}
|
||||
function runBatchedUpdates() {
|
||||
// TODO: Sort components by depth such that parent components update first
|
||||
for (var i = 0; i < dirtyComponents.length; i++) {
|
||||
// If a component is unmounted before pending changes apply, ignore them
|
||||
// TODO: Queue unmounts in the same list to avoid this happening at all
|
||||
var component = dirtyComponents[i];
|
||||
if (component.isMounted()) {
|
||||
// If performUpdateIfNecessary happens to enqueue any new updates, we
|
||||
// shouldn't execute the callbacks until the next render happens, so
|
||||
// stash the callbacks first
|
||||
var callbacks = component._pendingCallbacks;
|
||||
component._pendingCallbacks = null;
|
||||
component.performUpdateIfNecessary();
|
||||
if (callbacks) {
|
||||
for (var j = 0; j < callbacks.length; j++) {
|
||||
callbacks[j].call(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// IE8 requires `catch` in order to use `finally`.
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function clearDirtyComponents() {
|
||||
dirtyComponents.length = 0;
|
||||
}
|
||||
|
||||
function flushBatchedUpdates() {
|
||||
// Run these in separate functions so the JIT can optimize
|
||||
try {
|
||||
runBatchedUpdates();
|
||||
} catch (e) {
|
||||
// IE 8 requires catch to use finally.
|
||||
throw e;
|
||||
} finally {
|
||||
dirtyComponents.length = 0;
|
||||
isBatchingUpdates = false;
|
||||
clearDirtyComponents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,8 +82,9 @@ function enqueueUpdate(component, callback) {
|
||||
'`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
|
||||
'isn\'t callable.'
|
||||
);
|
||||
ensureBatchingStrategy();
|
||||
|
||||
if (!isBatchingUpdates) {
|
||||
if (!batchingStrategy.isBatchingUpdates) {
|
||||
component.performUpdateIfNecessary();
|
||||
callback && callback();
|
||||
return;
|
||||
@@ -97,9 +101,29 @@ function enqueueUpdate(component, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
var ReactUpdatesInjection = {
|
||||
injectBatchingStrategy: function(_batchingStrategy) {
|
||||
invariant(
|
||||
_batchingStrategy,
|
||||
'ReactUpdates: must provide a batching strategy'
|
||||
);
|
||||
invariant(
|
||||
typeof _batchingStrategy.batchedUpdates === 'function',
|
||||
'ReactUpdates: must provide a batchedUpdates() function'
|
||||
);
|
||||
invariant(
|
||||
typeof _batchingStrategy.isBatchingUpdates === 'boolean',
|
||||
'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
|
||||
);
|
||||
batchingStrategy = _batchingStrategy;
|
||||
}
|
||||
};
|
||||
|
||||
var ReactUpdates = {
|
||||
batchedUpdates: batchedUpdates,
|
||||
enqueueUpdate: enqueueUpdate
|
||||
enqueueUpdate: enqueueUpdate,
|
||||
flushBatchedUpdates: flushBatchedUpdates,
|
||||
injection: ReactUpdatesInjection
|
||||
};
|
||||
|
||||
module.exports = ReactUpdates;
|
||||
|
||||
Reference in New Issue
Block a user