@samitouri / QOS-React / commits / 64e7602b3b

Fix unmounting performance regression in V8 (#7232)

As reported in #7227, unmounting performance regressed with React 15. It seems that `delete` has become much slower since we started using numeric keys. Forcing dictionary keys to start with a dot fixes the issue.

Dan Abramov committed Jul 9, 2016 at 01:32 UTC 64e7602b3b9af9a43fd2f3495d3b13a398bb94d9
2 files changed +25 -13
src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
+10 -6
@@ -483,6 +483,10 @@ for (var type in topLevelEventsToDispatchConfig) {
483 var ON_CLICK_KEY = keyOf({onClick: null});
484 var onClickListeners = {};
485
486 +function getDictionaryKey(inst) {
487 + return '.' + inst._rootNodeID;
488 +}
489 +
490 var SimpleEventPlugin = {
491
492 eventTypes: eventTypes,
@@ -620,10 +624,10 @@ var SimpleEventPlugin = {
624 // fire. The workaround for this bug involves attaching an empty click
625 // listener on the target node.
626 if (registrationName === ON_CLICK_KEY) {
623 - var id = inst._rootNodeID;
627 + var key = getDictionaryKey(inst);
628 var node = ReactDOMComponentTree.getNodeFromInstance(inst);
625 - if (!onClickListeners[id]) {
626 - onClickListeners[id] = EventListener.listen(
629 + if (!onClickListeners[key]) {
630 + onClickListeners[key] = EventListener.listen(
631 node,
632 'click',
633 emptyFunction
@@ -634,9 +638,9 @@ var SimpleEventPlugin = {
638
639 willDeleteListener: function(inst, registrationName) {
640 if (registrationName === ON_CLICK_KEY) {
637 - var id = inst._rootNodeID;
638 - onClickListeners[id].remove();
639 - delete onClickListeners[id];
641 + var key = getDictionaryKey(inst);
642 + onClickListeners[key].remove();
643 + delete onClickListeners[key];
644 }
645 },
646
src/renderers/shared/stack/event/EventPluginHub.js
+15 -7
@@ -53,6 +53,10 @@ var executeDispatchesAndReleaseTopLevel = function(e) {
53 return executeDispatchesAndRelease(e, false);
54 };
55
56 +var getDictionaryKey = function(inst) {
57 + return '.' + inst._rootNodeID;
58 +};
59 +
60 /**
61 * This is a unified interface for event plugins to be installed and configured.
62 *
@@ -96,7 +100,7 @@ var EventPluginHub = {
100 },
101
102 /**
99 - * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
103 + * Stores `listener` at `listenerBank[registrationName][key]`. Is idempotent.
104 *
105 * @param {object} inst The instance, which is the source of events.
106 * @param {string} registrationName Name of listener (e.g. `onClick`).
@@ -109,9 +113,10 @@ var EventPluginHub = {
113 registrationName, typeof listener
114 );
115
116 + var key = getDictionaryKey(inst);
117 var bankForRegistrationName =
118 listenerBank[registrationName] || (listenerBank[registrationName] = {});
114 - bankForRegistrationName[inst._rootNodeID] = listener;
119 + bankForRegistrationName[key] = listener;
120
121 var PluginModule =
122 EventPluginRegistry.registrationNameModules[registrationName];
@@ -127,7 +132,8 @@ var EventPluginHub = {
132 */
133 getListener: function(inst, registrationName) {
134 var bankForRegistrationName = listenerBank[registrationName];
130 - return bankForRegistrationName && bankForRegistrationName[inst._rootNodeID];
135 + var key = getDictionaryKey(inst);
136 + return bankForRegistrationName && bankForRegistrationName[key];
137 },
138
139 /**
@@ -146,7 +152,8 @@ var EventPluginHub = {
152 var bankForRegistrationName = listenerBank[registrationName];
153 // TODO: This should never be null -- when is it?
154 if (bankForRegistrationName) {
149 - delete bankForRegistrationName[inst._rootNodeID];
155 + var key = getDictionaryKey(inst);
156 + delete bankForRegistrationName[key];
157 }
158 },
159
@@ -156,12 +163,13 @@ var EventPluginHub = {
163 * @param {object} inst The instance, which is the source of events.
164 */
165 deleteAllListeners: function(inst) {
166 + var key = getDictionaryKey(inst);
167 for (var registrationName in listenerBank) {
168 if (!listenerBank.hasOwnProperty(registrationName)) {
169 continue;
170 }
163 -
164 - if (!listenerBank[registrationName][inst._rootNodeID]) {
171 +
172 + if (!listenerBank[registrationName][key]) {
173 continue;
174 }
175
@@ -171,7 +179,7 @@ var EventPluginHub = {
179 PluginModule.willDeleteListener(inst, registrationName);
180 }
181
174 - delete listenerBank[registrationName][inst._rootNodeID];
182 + delete listenerBank[registrationName][key];
183 }
184 },
185