Fix perf regressions in _.bind, _.groupBy, _.countBy, _.indexBy, and _.reduceRight.

Former-commit-id: 0972dd65af64b7cd1d7f2800a8a59c28183b8aba
This commit is contained in:
John-David Dalton
2013-08-24 23:32:04 -07:00
parent 21db7d438b
commit 277557cd99
8 changed files with 409 additions and 279 deletions

132
dist/lodash.compat.js vendored
View File

@@ -1382,10 +1382,20 @@
return function(collection, callback, thisArg) {
var result = {};
callback = lodash.createCallback(callback, thisArg, 3);
forEach(collection, function(value, key, collection) {
key = String(callback(value, key, collection));
setter(result, value, key, collection);
});
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
setter(result, value, callback(value, index, collection), collection);
}
} else {
baseEach(collection, function(value, key, collection) {
setter(result, value, callback(value, key, collection), collection);
});
}
return result;
};
}
@@ -1418,18 +1428,31 @@
isCurry = bitmask & 4,
isCurryBound = bitmask & 8,
isPartial = bitmask & 16,
isPartialRight = bitmask & 32;
isPartialRight = bitmask & 32,
key = func;
if (!isBindKey && !isFunction(func)) {
throw new TypeError;
}
if (isPartial && !partialArgs.length) {
bitmask &= ~16;
isPartial = partialArgs = false;
}
if (isPartialRight && !partialRightArgs.length) {
bitmask &= ~32;
isPartialRight = partialRightArgs = false;
}
// use `Function#bind` if it exists and is fast
// (in V8 `Function#bind` is slower except when partially applied)
if (isBind && !(isBindKey || isCurry || isPartialRight) &&
(support.fastBind || (nativeBind && partialArgs.length))) {
var args = [func, thisArg];
push.apply(args, partialArgs);
var bound = nativeBind.call.apply(nativeBind, args);
(support.fastBind || (nativeBind && isPartial))) {
if (isPartial) {
var args = [thisArg];
push.apply(args, partialArgs);
}
var bound = isPartial
? nativeBind.apply(func, args)
: nativeBind.call(func, thisArg);
}
else {
bound = function() {
@@ -1438,14 +1461,14 @@
var args = arguments,
thisBinding = isBind ? thisArg : this;
if (partialArgs) {
if (isPartial) {
unshift.apply(args, partialArgs);
}
if (partialRightArgs) {
if (isPartialRight) {
push.apply(args, partialRightArgs);
}
if (isCurry && args.length < arity) {
bitmask |= 16 & ~32
bitmask |= 16 & ~32;
return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity);
}
if (isBindKey) {
@@ -1463,10 +1486,6 @@
return func.apply(thisBinding, args);
};
}
if (isBindKey) {
var key = thisArg;
thisArg = func;
}
return bound;
}
@@ -3285,17 +3304,25 @@
var iterable = collection,
length = collection ? collection.length : 0;
if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
if (isArray(collection)) {
while (length--) {
if (callback(collection[length], length, collection) === false) {
break;
}
}
} else {
if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
}
baseEach(collection, function(value, key, collection) {
key = props ? props[--length] : --length;
return callback(iterable[key], key, collection);
});
}
callback = baseCreateCallback(callback, thisArg, 3);
forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length;
return callback(iterable[index], index, collection);
});
return collection;
}
@@ -4317,7 +4344,7 @@
var index = sortedIndex(array, value);
return array[index] === value ? index : -1;
}
return array ? baseIndexOf(array, value, fromIndex) : -1;
return baseIndexOf(array, value, fromIndex);
}
/**
@@ -5083,7 +5110,7 @@
while (++index < length) {
var key = funcs[index];
object[key] = bind(object[key], object);
object[key] = createBound(object[key], 1, null, null, object);
}
return object;
}
@@ -5123,7 +5150,7 @@
* // => 'hi, moe!'
*/
function bindKey(object, key) {
return createBound(object, 19, nativeSlice.call(arguments, 2), null, key);
return createBound(key, 19, nativeSlice.call(arguments, 2), null, object);
}
/**
@@ -5319,6 +5346,7 @@
function debounce(func, wait, options) {
var args,
result,
stamp,
thisArg,
callCount = 0,
lastCalled = 0,
@@ -5339,24 +5367,30 @@
maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0);
trailing = 'trailing' in options ? options.trailing : trailing;
}
var clear = function() {
clearTimeout(maxTimeoutId);
clearTimeout(timeoutId);
callCount = 0;
maxTimeoutId = timeoutId = null;
};
var delayed = function() {
var isCalled = trailing && (!leading || callCount > 1);
clear();
if (isCalled) {
lastCalled = +new Date;
result = func.apply(thisArg, args);
var remaining = wait - (new Date - stamp);
if (remaining <= 0) {
var isCalled = trailing && (!leading || callCount > 1);
if (maxTimeoutId) {
clearTimeout(maxTimeoutId);
}
callCount = 0;
maxTimeoutId = timeoutId = null;
if (isCalled) {
lastCalled = +new Date;
result = func.apply(thisArg, args);
}
} else {
timeoutId = setTimeout(delayed, remaining);
}
};
var maxDelayed = function() {
clear();
if (timeoutId) {
clearTimeout(timeoutId);
}
callCount = 0;
maxTimeoutId = timeoutId = null;
if (trailing || (maxWait !== wait)) {
lastCalled = +new Date;
result = func.apply(thisArg, args);
@@ -5365,26 +5399,24 @@
return function() {
args = arguments;
stamp = +new Date;
thisArg = this;
callCount++;
// avoid issues with Titanium and `undefined` timeout ids
// https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192
clearTimeout(timeoutId);
if (maxWait === false) {
if (leading && callCount < 2) {
result = func.apply(thisArg, args);
}
} else {
var stamp = +new Date;
if (!maxTimeoutId && !leading) {
lastCalled = stamp;
}
var remaining = maxWait - (stamp - lastCalled);
if (remaining <= 0) {
clearTimeout(maxTimeoutId);
maxTimeoutId = null;
if (maxTimeoutId) {
clearTimeout(maxTimeoutId);
maxTimeoutId = null;
}
lastCalled = stamp;
result = func.apply(thisArg, args);
}
@@ -5392,7 +5424,7 @@
maxTimeoutId = setTimeout(maxDelayed, remaining);
}
}
if (wait !== maxWait) {
if (!timeoutId && wait !== maxWait) {
timeoutId = setTimeout(delayed, wait);
}
return result;