Skip to content

Instantly share code, notes, and snippets.

@jed
Created June 23, 2010 10:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jed/449728 to your computer and use it in GitHub Desktop.
Save jed/449728 to your computer and use it in GitHub Desktop.
var puts = require( "sys" ).puts
, contextFn = function( a ){ return a && this() }
, argFn = function( a, b ){ return b && a() }
, time;
time = +new Date;
for ( var i = 0; i < 10e6; i++ ) contextFn.call( contextFn, contextFn );
puts( "as context: " + ( +new Date - time ) );
time = +new Date;
for ( var i = 0; i < 10e6; i++ ) argFn( argFn, argFn );
puts( "as argument: " + ( +new Date - time ) );
@jed
Copy link
Author

jed commented Jun 23, 2010

results are usually like this for me:

as context: 356
as argument: 161

is this a valid way of testing the overhead of setting a context for a function call?

@felixge
Copy link

felixge commented Jun 25, 2010

No, you need to access the passed parameter / this. Otherwise the compiler might optimize things in a way that will mess with the results.

@jed
Copy link
Author

jed commented Jun 25, 2010

okay, i'm accessing the arguments now, results on my machine are like this:

as context: 581
as argument: 314

what do you think?

@felixge
Copy link

felixge commented Jun 25, 2010

well, I'm not surprised argument passing is faster : ), but your test should be more fair now.

But I'm actually confused, shouldn't your test functions call themselves endlessly / recursively?

@jed
Copy link
Author

jed commented Jun 25, 2010

i don't think so, because they get short-circuited without the non-callback arg.

is a .000025ms hit per function worth it?

@felixge
Copy link

felixge commented Jun 25, 2010

Ah, right, on the first recursive call the functions return false, that explains it.

If it's worth it: How many fab functions are called per request? Is it just the ones on the matching path, or will all functions get called every time?

If it's just the hot path I doubt call will make a difference. However, are you just using 'call', or are you also using 'apply'? That could be an entirely different story

@jed
Copy link
Author

jed commented Jun 25, 2010

well, just the hot path. so if you have a bunch of chained ternary path apps, for example, all apps until the path is matched.

but yeah, the more binary your tree the fewer the apps, so i'd imagine it'd grow near O(log n) for a fairly balanced site.

is it true that call and apply have different performance? i don't think i'd be using apply, because each app only allows a single argument (the data payload). any use of apply would only pass the existing arguments object too, not an array or anything.

i'm leaning towards keeping this as the universal callback pattern, because:

  • it's one less thing i have to worry about naming for
  • it's more naturally omittable: app.call(cb,data) and app(data) vs. app(data,cb) and app(undefined,cb)
  • it keeps the functions "airtight", since all possible ways to pass data would be used
  • it avoids ambiguity: with app(data,cb), if data is undefined, i can't determine whether undefined was actually intended to be passed, or if data is supposed to be blank. with app.call(cb,data), i can look at arguments.length to disambiguate.

thoughts?

@felixge
Copy link

felixge commented Jun 26, 2010

apply is different because it can pass a variable number of arguments which is harder to optimize for V8. I have not benchmarked it, but I suspect it to be substantially slower than just call.

I think you should go ahead with 'this'. Everything else seems like pre-mature optimization at this point. I suspect other parts of fab to be substantially slower, so you shouldn't worry about this one for now : ).

@jed
Copy link
Author

jed commented Jun 26, 2010

thanks, felix. your feedback is very much appreciated!

@felixge
Copy link

felixge commented Jun 26, 2010

あなたは歓迎されて

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment