

John Resig Talk: Performance Improvements in Browsers - babyshake
http://ejohn.org/blog/talk-performance-improvements-in-browsers/

======
tlrobinson
Regarding testing JavaScript parse speed, why is it difficult to test in the
browser? Couldn't you, for example, wrap a string containing JavaScript code
in "function(){}" and pass it to eval, or do "new Function()", and not execute
the result?

As a corollary to that, doing

    
    
        eval("function(){"+code+"}")
    

is _much_ slower (~5x) than

    
    
        new Function(code)
    

at least in Firefox using 280slides.com as my test subject (which is part of
the reason we do use "new Function").

~~~
jeresig
new Function() /may/ work - but that's only if a browser actually parses the
code when you pass it in to the function. Maybe a browser is lazy and only
parses it when it's executed for the first time? (I know that's what I'd
probably do.) Of course then we're back to our original problem again - being
unable to find the difference between them.

To your second point: Of course eval("function(){"+code+"}" is going to be a
lot slower than new Function(code) - you're constructing a closure to any
external variables that are used (not to mention that using eval will have to
parse the full expression and return the result - rather than with new
Function which has a singular purpose).

~~~
tlrobinson
I suppose you could wrap the code in "if(false){ }" (or make the first
statement a "return" in the case of "new Function()") and actually execute it
to ensure it's being parsed, but we're entering hacky territory...

------
jwilliams
Interesting - particularly the difference between the type of benchmarks. I
shouldn't be too surprised I guess.

It's also interesting how little what we used to call "layout" is a
performance target any more.

~~~
jeresig
I've actually written about JavaScript benchmark quality before:
<http://ejohn.org/blog/javascript-benchmark-quality/>

(I've since re-written Dromaeo - and the current version that's live is taking
in to account all the problems that I outlined in this post.)

I think layout would be more of a performance target if there was a reliable
way to test it across platforms - or even on a single platform (especially so
from JavaScript). That's definitely something that I'd like to shoot for,
though - it would be hugely helpful to developers.

~~~
jwilliams
Thanks for the link.

I guess my thinking was -- I hear a lot of anecdotal discussion about the
FireFox codebase and how it needs to be re-engineered, etc, etc (ie. WebKit is
tidier and so forth).

If the performance war is elsewhere, does that remain a factor? i.e. Assuming
the above is actually true, does the codebase have legs as the performance war
is elsewhere?

~~~
jeresig
I think that the Firefox codebase is a lot of things. It's been around for a
while, for sure. There's cruft - definitely. It's also being actively stripped
of its cruft and being actively improved. I think a lot of people are coming
to discover just how much 'oompf' the Firefox codebase has. For example, all
of these huge JavaScript performance improvements (TraceMonkey) are a layer of
additions on top of the existing JavaScript engine (SpiderMonkey). So yeah,
there's some really smart people at Mozilla who are making the code base quite
fast - just as there are at Apple, Opera, and Google. It's a great time to be
a web developers - this performance battle is just awesome on so many levels.

------
sam_in_nyc
Hey John, while I've possibly got your attention, I've got a question
regarding performance on IE. This one, to this day, I cannot explain.

The gist of it is: I do "document.attachEvent("onmousemove", fn)" where fn
resizes a div based on where the cursor is. I then test it out, and it's slow
as hell, especially when the div gets pretty big. In fact, the event only
seems to fire when I move the mouse slowly.

Now here's the catch. I bind the event _again_ so that the function is bound
_twice_ to onmousemove, and performance is vastly improved!

How could it be that binding a function twice to an event speeds it up? Three
times has no further effect... beyond that I haven't tested.

EDIT: Go to my profile to see the bug in action. While resizing a div (which
contains 2 iframes), it's much much smoother with the "mousemove" event
attached twice.

~~~
jeresig
Hmm, I'm really not sure what the issue is, off-hand. It doesn't seem like
you're hugely interested - but this is definitely what libraries are for
(making annoyingly complex interactions like this possible). The jQuery UI
Draggables are quite good (for example):
<http://ui.jquery.com/demos/draggable/>

~~~
sam_in_nyc
I use jQuery all the time, I purposefully left it out of this example to
reduce the number of variables causing the IE performance quirk.

I've found that jQuery UI plugins are bloated and slow, to be honest. There
focus is on providing a dead simple interface to the developer, who might not
even know how to code. I believe this leads to bloating the code and degrading
performance, since the code now has to check for and include tons of these
little edge cases, which can even compound themselves when they're used at the
same time. In the "draggable" demos, anything being dragged is quite laggy and
choppy, at least in FF, when it definitely shouldn't be.

jQuery already makes it easy enough to build whatever functionality I want,
including drag and drop... and since it's not generalized (as in the case of
jUI) it's fast. For drag and drop, 50 lines was all it took to pretty much
copy the entire functionality of jQuery draggables... assuming the developer
can code a _tiny bit_ of functionality himself. Rather than cram all sorts of
microfeatures, like "vertical-only" and "hortizontal-only", I abstract the
problem out so that it puts more control in the developer's hands, but still
is dead simple.

In my case, the developer defines the "init" function (triggered after it's
dragged for a given length or time), the "move" function (which is passed
deltaX and deltaY) and the "end" function, all of which are passed events as
well. If he can't use this information to make something resize (which is just
adding deltaX to originalWidth), for example, then that's too bad, he will
have to use 42kb of jUI code to do it.

Another example of bloat and poor performance... if you wanted to create a
Dialog, it requires Draggable, and Sortable, and comes to a total of 84kb
(uncompressed). It's so laggy then when you're moving it around the shadow
appears to be chasing the dialog... and resizing it lags half upwards of half
a second. With jQuery, I've made draggable, resizable, shadowed dialogs in
like 200 lines.

------
tlrobinson
Looks like this talk just missed Opera's announcement of their own new JS
engine:

<http://my.opera.com/core/blog/2009/02/04/carakan>

~~~
jeresig
Yep - but at the same time, it's not like I could've provided better data or
more information - they have yet to release any code (and it's not even going
to be in Opera 10 - so who knows if it'll even be out in 2009). I don't like
working on speculation, I love having code in my hands, though :-)

------
daleharvey
I have been looking through javascript performance videos quite a lot
recently, not entirely applicable to this video, but one problem I see is that
firebug are great at profiling "userland" javascript, but there doesnt seem to
be much information about how to measure the time spent in reflow and repaint,
its basically guesswork of removing nodes from the dom / absolutely
positioning thing etc.

------
sam_in_nyc
John has such an awesome job. I'd love to work with Javascript all day long...
which is in fact what I do... except get paid for it and have a sweet title.

I love Javascript so much. The fact that it has "function.call(object, other,
params)" pretty much sums it up... a function can work with any object, and
vice versa.

~~~
ksvs
_function.call(object, other, params)_

Can you explain what this does? It sounds interesting, but I don't know
Javascript.

~~~
andreyf
Basically,

    
    
      foo.barMethod("Hello", "World")
    

is identical to:

    
    
      someFunction.call(foo, "Hello", "World");
    

(assuming that foo.barMethod === someFunction)

This is a little weirder than it seems, because of a variable called `this'.
You see, `this' is set inside of a function whenever you call it, based on how
you've called it. It can be set a couple of ways:

    
    
      foo(arg1, arg2, ...); // sets `this' to the global object (in a browser, that's `window')
      foo.call(o, arg1, arg2, ...); // sets `this' to `o'
      foo.apply(o, [arg1, arg2, ...]); // sets `this' to `o' (same as `call')
    

None of these are the way you usually set `this' on function invocation,
however. Usually, `this' is set automatically when you invoke a function which
happens to be a property of an object. So, for example:

    
    
      bar = { foo: function (x,y) { var thatThing = this; ... } };
      bar.foo(1,2) - sets `this' (and `thatThing') to 'bar'.
    

However (!!!), if you say:

    
    
      foo2 = bar.foo;
      foo2();
    

The `this' inside of your function, as well as `thatThing', will both be set
to `window'.

details here:
[https://developer.mozilla.org/en/Core_JavaScript_1.5_Referen...](https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function/call)

~~~
kragen
Is it really _window_? I thought it was just the value of _this_ in the caller
of _foo2()_ — which might happen to be _window_ or something else.

~~~
koningrobot
_blows dust off JavaScript skills..._

'this' is always 'window', unless the function is invoked as a method, i.e.,
as a property of an object:

    
    
        window.bar = 'bar'
        var obj = {
            foo: function () { return this.bar },
            bar: 'foo'
        };
    
        obj.foo() === 'foo';         // invoked as a method
    
        foo = obj.foo;
        foo() === 'bar';             // invoked as a function
    
        // this reveals some oddness imho:
        (obj.foo)() === 'foo';       // invoked as a method
        (foo = obj.foo)() === 'bar'; // invoked as a function
    

Note that 'this' defaults to 'window' _not_ because 'foo()' is equivalent to
'window.foo()'; 'foo' could be a local variable referring to a function and
'this' would refer to 'window' all the same. There's no rationale for this
that I know of, it's just the way it works (in ES3 at least: ES4 does what you
expected).

When you use the Function::call and Function::apply methods, you get to
specify what 'this' should refer to:

    
    
        obj.foo.call(window) === 'bar';
        foo.apply(obj, [])   === 'foo';
    

'call' and 'apply' are the same, except that apply takes an array of function
arguments, whereas call takes arguments directly.

Note that the terms 'method' and 'function' are my own here, I'm not sure what
to call the two forms of invocation.

~~~
axod
>> "'this' is always 'window', unless the function is invoked as a method,
i.e., as a property of an object:"

More generally, 'this' is usually 'the global object'... would be more
correct. And in a browser context, the global object is 'window'.

------
robotron
The x-domain stuff is very cool and will be extremely useful. I'm scared what
black hats will do with it, though.

