Fix a few GC leaks in events system
Summary: - Weren't pooling the Transaction in the batching strategy - Creating a new closure for every event tick due to batchedUpdates() - EnterLeaveEventPlugin creates a new array on each event. I wonder if there is more optimization opportunity in accumulate(). Squinting at the fps graph this seems to be faster and waste less memory but it's hard to conclusively tell. I did verify that these were all hotspots though.
Pete Hunt committed
Sep 3, 2013 at 14:15 UTC
406dcbd8daa8bf6e17348006c938168ab6c08e53
4 files changed
+20
-11
src/core/ReactDefaultBatchingStrategy.js
+5
-4
@@ -49,6 +49,8 @@ mixInto(ReactDefaultBatchingStrategyTransaction, {
49
}
50
});
51
52
+var transaction = new ReactDefaultBatchingStrategyTransaction();
53
+
54
var ReactDefaultBatchingStrategy = {
55
isBatchingUpdates: false,
56
@@ -56,17 +58,16 @@ var ReactDefaultBatchingStrategy = {
58
* Call the provided function in a context within which calls to `setState`
59
* and friends are batched such that components aren't updated unnecessarily.
60
*/
59
- batchedUpdates: function(callback) {
61
+ batchedUpdates: function(callback, param) {
62
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
63
64
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
65
66
// The code is written this way to avoid extra allocations
67
if (alreadyBatchingUpdates) {
66
- callback();
68
+ callback(param);
69
} else {
68
- var transaction = new ReactDefaultBatchingStrategyTransaction();
69
- transaction.perform(callback);
70
+ transaction.perform(callback, null, param);
71
}
72
}
73
};
src/core/ReactEventEmitterMixin.js
+6
-4
@@ -21,6 +21,11 @@
21
var EventPluginHub = require('EventPluginHub');
22
var ReactUpdates = require('ReactUpdates');
23
24
+function runEventQueueInBatch(events) {
25
+ EventPluginHub.enqueueEvents(events);
26
+ EventPluginHub.processEventQueue();
27
+}
28
+
29
var ReactEventEmitterMixin = {
30
/**
31
* Whether or not `ensureListening` has been invoked.
@@ -77,10 +82,7 @@ var ReactEventEmitterMixin = {
82
);
83
84
// Event queue being processed in the same cycle allows `preventDefault`.
80
- ReactUpdates.batchedUpdates(function() {
81
- EventPluginHub.enqueueEvents(events);
82
- EventPluginHub.processEventQueue();
83
- });
85
+ ReactUpdates.batchedUpdates(runEventQueueInBatch, events);
86
}
87
};
88
src/core/ReactUpdates.js
+2
-2
@@ -28,9 +28,9 @@ function ensureBatchingStrategy() {
28
invariant(batchingStrategy, 'ReactUpdates: must inject a batching strategy');
29
}
30
31
-function batchedUpdates(callback) {
31
+function batchedUpdates(callback, param) {
32
ensureBatchingStrategy();
33
- batchingStrategy.batchedUpdates(callback);
33
+ batchingStrategy.batchedUpdates(callback, param);
34
}
35
36
function runBatchedUpdates() {
src/eventPlugins/EnterLeaveEventPlugin.js
+7
-1
@@ -35,6 +35,8 @@ var eventTypes = {
35
mouseLeave: {registrationName: keyOf({onMouseLeave: null})}
36
};
37
38
+var extractedEvents = [null, null];
39
+
40
var EnterLeaveEventPlugin = {
41
42
eventTypes: eventTypes,
@@ -99,7 +101,11 @@ var EnterLeaveEventPlugin = {
101
);
102
103
EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
102
- return [leave, enter];
104
+
105
+ extractedEvents[0] = leave;
106
+ extractedEvents[1] = enter;
107
+
108
+ return extractedEvents;
109
}
110
111
};