Merge pull request #2054 from chenglou/accum

[RFC] Use `accumulateInto` to save even more allocation
This commit is contained in:
Cheng Lou
2014-08-20 13:36:45 -07:00
6 changed files with 152 additions and 16 deletions
@@ -23,7 +23,7 @@ var EventPluginUtils = require('EventPluginUtils');
var EventPropagators = require('EventPropagators');
var SyntheticEvent = require('SyntheticEvent');
var accumulate = require('accumulate');
var accumulateInto = require('accumulateInto');
var keyOf = require('keyOf');
var isStartish = EventPluginUtils.isStartish;
@@ -212,7 +212,7 @@ function setResponderAndExtractTransfer(
nativeEvent
);
EventPropagators.accumulateDirectDispatches(terminateEvent);
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
extracted = accumulateInto(extracted, [grantEvent, terminateEvent]);
responderID = wantsResponderID;
} else {
var rejectEvent = SyntheticEvent.getPooled(
@@ -221,10 +221,10 @@ function setResponderAndExtractTransfer(
nativeEvent
);
EventPropagators.accumulateDirectDispatches(rejectEvent);
extracted = accumulate(extracted, rejectEvent);
extracted = accumulateInto(extracted, rejectEvent);
}
} else {
extracted = accumulate(extracted, grantEvent);
extracted = accumulateInto(extracted, grantEvent);
responderID = wantsResponderID;
}
return extracted;
@@ -288,7 +288,7 @@ var ResponderEventPlugin = {
nativeEvent
);
if (transfer) {
extracted = accumulate(extracted, transfer);
extracted = accumulateInto(extracted, transfer);
}
}
// Now that we know the responder is set correctly, we can dispatch
@@ -303,7 +303,7 @@ var ResponderEventPlugin = {
nativeEvent
);
EventPropagators.accumulateDirectDispatches(gesture);
extracted = accumulate(extracted, gesture);
extracted = accumulateInto(extracted, gesture);
}
if (type === eventTypes.responderRelease) {
responderID = null;
@@ -20,7 +20,7 @@
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var accumulate = require('accumulate');
var accumulateInto = require('accumulateInto');
var forEachAccumulated = require('forEachAccumulated');
var invariant = require('invariant');
@@ -36,7 +36,8 @@ var LocalEventTrapMixin = {
handlerBaseName,
this.getDOMNode()
);
this._localEventListeners = accumulate(this._localEventListeners, listener);
this._localEventListeners =
accumulateInto(this._localEventListeners, listener);
},
// trapCapturedEvent would look nearly identical. We don't implement that
+3 -3
View File
@@ -21,7 +21,7 @@
var EventPluginRegistry = require('EventPluginRegistry');
var EventPluginUtils = require('EventPluginUtils');
var accumulate = require('accumulate');
var accumulateInto = require('accumulateInto');
var forEachAccumulated = require('forEachAccumulated');
var invariant = require('invariant');
var isEventSupported = require('isEventSupported');
@@ -236,7 +236,7 @@ var EventPluginHub = {
nativeEvent
);
if (extractedEvents) {
events = accumulate(events, extractedEvents);
events = accumulateInto(events, extractedEvents);
}
}
}
@@ -252,7 +252,7 @@ var EventPluginHub = {
*/
enqueueEvents: function(events) {
if (events) {
eventQueue = accumulate(eventQueue, events);
eventQueue = accumulateInto(eventQueue, events);
}
},
+7 -5
View File
@@ -21,7 +21,7 @@
var EventConstants = require('EventConstants');
var EventPluginHub = require('EventPluginHub');
var accumulate = require('accumulate');
var accumulateInto = require('accumulateInto');
var forEachAccumulated = require('forEachAccumulated');
var PropagationPhases = EventConstants.PropagationPhases;
@@ -52,8 +52,9 @@ function accumulateDirectionalDispatches(domID, upwards, event) {
var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
var listener = listenerAtPhase(domID, event, phase);
if (listener) {
event._dispatchListeners = accumulate(event._dispatchListeners, listener);
event._dispatchIDs = accumulate(event._dispatchIDs, domID);
event._dispatchListeners =
accumulateInto(event._dispatchListeners, listener);
event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
}
}
@@ -85,8 +86,9 @@ function accumulateDispatches(id, ignoredDirection, event) {
var registrationName = event.dispatchConfig.registrationName;
var listener = getListener(id, registrationName);
if (listener) {
event._dispatchListeners = accumulate(event._dispatchListeners, listener);
event._dispatchIDs = accumulate(event._dispatchIDs, id);
event._dispatchListeners =
accumulateInto(event._dispatchListeners, listener);
event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
}
}
}
@@ -0,0 +1,64 @@
/**
* Copyright 2014 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.
*
* @emails react-core
* @jsx React.DOM
*/
"use strict";
require('mock-modules')
.dontMock('accumulateInto');
var accumulateInto;
describe('accumulateInto', function() {
beforeEach(function() {
accumulateInto = require('accumulateInto');
});
it('throws if the second item is null', function() {
expect(function() {
accumulateInto([], null);
}).toThrow(
'Invariant Violation: accumulateInto(...): Accumulated items must not ' +
'be null or undefined.'
);
});
it('returns the second item if first is null', function() {
var a = [];
expect(accumulateInto(null, a)).toBe(a);
});
it('merges the second into the first if first item is an array', function() {
var a = [1, 2];
var b = [3, 4];
accumulateInto(a, b);
expect(a).toEqual([1, 2, 3, 4]);
expect(b).toEqual([3, 4]);
var c = [1];
accumulateInto(c, 2);
expect(c).toEqual([1, 2]);
});
it('returns a new array if first or both items are scalar', function() {
var a = [2];
expect(accumulateInto(1, a)).toEqual([1, 2]);
expect(a).toEqual([2]);
expect(accumulateInto(1, 2)).toEqual([1, 2]);
});
});
+69
View File
@@ -0,0 +1,69 @@
/**
* Copyright 2014 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 accumulateInto
*/
"use strict";
var invariant = require('invariant');
/**
*
* Accumulates items that must not be null or undefined into the first one. This
* is used to conserve memory by avoiding array allocations, and thus sacrifices
* API cleanness. Since `current` can be null before being passed in and not
* null after this function, make sure to assign it back to `current`:
*
* `a = accumulateInto(a, b);`
*
* This API should be sparingly used. Try `accumulate` for something cleaner.
*
* @return {*|array<*>} An accumulation of items.
*/
function accumulateInto(current, next) {
invariant(
next != null,
'accumulateInto(...): Accumulated items must not be null or undefined.'
);
if (current == null) {
return next;
}
// Both are not empty. Warning: Never call x.concat(y) when you are not
// certain that x is an Array (x could be a string with concat method).
var currentIsArray = Array.isArray(current);
var nextIsArray = Array.isArray(next);
if (currentIsArray && nextIsArray) {
current.push.apply(current, next);
return current;
}
if (currentIsArray) {
current.push(next);
return current;
}
if (nextIsArray) {
// A bit too dangerous to mutate `next`.
return [current].concat(next);
}
return [current, next];
}
module.exports = accumulateInto;