Is there a performance benefit in switching from func.apply(obj, params) to func.call(obj) when params is an empty array or null?
I mean, is calling func.call(obj) any faster than calling func.apply(obj, null)?
I'm mostly interested in performance under NodeJS 4.x.
This is for an algorithm that has to make a lot of such calls.
-
2I realize that such an algorithm may make a lot of those calls, but its usually premature optimization to worry about such a trivial detail that bloats your code before profiling.Jared Smith– Jared Smith2015年10月10日 14:16:19 +00:00Commented Oct 10, 2015 at 14:16
-
This is not being helpful. I'm asking for some real numbers for this sort of optimization, not to tell me how to do my own measurements or approach writing my algorithm.vitaly-t– vitaly-t2015年10月10日 14:21:03 +00:00Commented Oct 10, 2015 at 14:21
-
The thing is, as with almost all micro-optimization, that the actual performance of a minuscule operation like this is dependent on the algorithm that uses it. You might well find that in isolated cases one is faster than the other, but in practice it's the other way around. There's no way to know for sure without trying it in the real use case.JJJ– JJJ2015年10月10日 14:24:20 +00:00Commented Oct 10, 2015 at 14:24
-
In my case I have to rely heavily on this kind of calls. Anyhow, the answer by Magu is excellent, and the numbers speak for themselves!vitaly-t– vitaly-t2015年10月10日 14:27:52 +00:00Commented Oct 10, 2015 at 14:27
-
Well the difference is 0.00000003 seconds per operation on my computer... but sure, if you have a million calls in a loop you'll save 30 milliseconds.JJJ– JJJ2015年10月10日 15:37:56 +00:00Commented Oct 10, 2015 at 15:37
3 Answers 3
On this page there is a comparison. https://jsperf.com/call-apply-segu Call was faster on my machine.
Comments
Basically, they will do the same steps:
Function.prototype.apply (thisArg, argArray)
- If IsCallable(func) is false, then throw a TypeError exception.
- If argArray is null or undefined, then
- Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and an empty list of arguments.
Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] )
- If IsCallable(func) is false, then throw a TypeError exception.
- Let argList be an empty List.
- If this method was called with more than one argument then in left to right order starting with arg1 append each argument as the last element of argList
- Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
So the difference, if any, should be implementation dependent, and negligible.
1 Comment
Ha, interesting: it looks like apply is slower than call. 8-)
~/tmp ω cat test.js
function work(a, b, c) {
// do some work
}
var a = [1, 2, 3];
for (var j = 0; j < 4; j++) {
console.time('apply-ing');
for (var i = 0; i < 1000000; i++) {
work.apply(this, a);
}
console.timeEnd('apply-ing');
console.time('call-ing');
for (var i = 0; i < 1000000; i++) {
work.call(this, 1, 2, 3);
}
console.timeEnd('call-ing');
}
~/tmp ω node test.js
apply-ing: 42ms
call-ing: 5ms
apply-ing: 40ms
call-ing: 5ms
apply-ing: 42ms
call-ing: 5ms
apply-ing: 39ms
call-ing: 6ms
~/tmp ω node --version
v4.1.2
~/tmp ω
2 Comments
apply is a lot slower than call.call like this work.call(this, ...a). And apply will win. Just only because apply here uses argument config as an argument. It's more useful for realworld