IE+JScript Performance Recommendations Part 3: JavaScript Code Inefficiencies


Hello again, this is Peter Gurevich, Performance PM for IE. We have gotten a lot of good feedback from our first posts on IE + JavaScript Performance Recommendations Part 1 and Part 2, so I am eager to hear what you think of our third installment.

JScript Code Inefficiencies – Chapter 2

Here we’ll be concentrating on specific inefficiencies related to closures and object oriented programming.

Avoid Closures if Possible

Closures (functions that refer to free variables in their lexical context) are both extremely powerful and extremely dangerous. There are certain programming techniques that demand their use and once you learn how to use them they can quickly become one of the most overused features of the JScript language. Currently the misuse of closures in connection with the IE DOM and various COM components are the number one cause of heightened memory usage within IE. Also, while they are useful, this is a performance article and there are not really any scenarios where a closure is going to provide more performance throughput than a bare function or inline code.

Closures are most often used when attaching event handlers. The purpose in this case is to encapsulate some of the scope for the currently running function into a brand new function that can later be used when the event handler is invoked. The trouble with this approach is that circular references between the scoped variables and the closure are nearly invisible to the eye. The extra memory pressure of leaving these objects around means extra garbage collection pressure, possibly extra work for IE, or more bookkeeping for other hosts. APIs for handling the retrieval of remote data are useful as an example.

function startDownload(url)
{
      var source = new ActiveXObject(“Ficitious.UrlFetcher”);
      source.ondataready = new function() { source.ondataready = null; }
      source.startRequest(url);
}

The above example is pretty basic. The script doesn’t do any real work, but sets up a mock scenario of a closure. What happens when the ondataready event never fires? We expect it to, but it might not. If it doesn’t fire, the closure in this case has a reference to the source object and the source object back to the closure. This is an implicit circular reference, hard to spot, and IE leaks memory. This is never good for performance. Furthermore, every time the startDownload function is called, it means allocating a new object to store all of this state. Rewriting the sample to not use closures is very specific to your application. If you only allow a single instance of the object to exist, then you could take advantage of a global singleton. If you allow multiple requests, then a pooling mechanism is probably more appropriate along with a method for dispatching and handling all incoming requests even if a particular request is signaling it is ready. For additional information on closures, please see the Closures section in Understanding and Solving Internet Explorer Leak Patterns.

Don’t use Property Accessor Functions

A common technique in object oriented programming is to use property accessor functions. An example would be in the form of [get/set]_PropertyName (or many others depending on the style). The basic premise is a local member variable for some class followed by two methods for either retrieving or setting the property. These methods are often used for controlling member visibility, but in JScript everything is visible. Further, most object oriented languages optimize the property methods away to direct variable access during compilation, not so with interpreted JScript. A quick attempt at coding a simple Car object might produce code with property accessors:

function Car()
{
      this.m_tireSize = 17;
      this.m_maxSpeed = 250; // One can always dream!
      this.GetTireSize = Car_get_tireSize;
      this.SetTireSize = Car_put_tireSize;
}
function Car_get_tireSize()
{
      return this.m_tireSize;
}
function Car_put_tireSize(value)
{
      this.m_tireSize = value;
}

var ooCar = new Car();
var iTireSize = ooCar.GetTireSize();
ooCar.SetTireSize(iTireSize + 1); // An upgrade

The above is pretty good object oriented but terrible JScript. The extra indirection in accessing our local members is really hurting the performance of the application. Unless we need to do validation of the incoming values, the code should never add extra indirection and should be as precise as possible. Rewriting the above is an exercise in removing as much extra code as possible.

function Car()
{
      this.m_tireSize = 17;
      this.m_maxSpeed = 250; // One can always dream!
}
var perfCar = new Car();
var iTireSize = perfCar.m_tireSize;
perfCar.m_tireSize = iTireSize + 1; // An upgrade

We’ve removed two extra expando properties on the object, a couple of functions, some extra work while retrieving and setting our properties, and a few name binds. In short, try to stay away from any extra indirection.

For a more complete sample, we can also add prototypes. Note that prototypes will actually be slower, since the instance will be searched first, then the prototype, and so functional look-ups occur more slowly. This will make our naïve sample slower for sure. If you are creating thousands of instances of the class, the prototypes start to become more efficient. They start by reducing the size of each object since extra properties are not added per instance that point to the same global functions. Further, object instantiation can be much faster since the extra property assignments are not needed to set up all of the functions. For completeness, here is a full sample. As an extra challenge, try to find scenarios where the prototype car wins over the slow car.

<script>
// Slow Car definition
function SlowCar()
{
      this.m_tireSize = 17;
      this.m_maxSpeed = 250; // One can always dream!
      this.GetTireSize = SlowCar_get_tireSize;
      this.SetTireSize = SlowCar_put_tireSize;
}
function SlowCar_get_tireSize()
{
      return this.m_tireSize;
}
function SlowCar_put_tireSize(value)
{
      this.m_tireSize = value;
}
</script>

<script>
// Faster Car, no more property accessors
function FasterCar()
{
      this.m_tireSize = 17;
      this.m_maxSpeed = 250; // One can always dream!
}
</script>

<script>
// Prototype Car, use the language features!
function PrototypeCar()
{
      this.m_tireSize = 17;
      this.m_maxSpeed = 250; // One can always dream!
}

PrototypeCar.prototype.GetTireSize = function() { return this.m_tireSize; };
PrototypeCar.prototype.SetTireSize = function(value) { this.m_tireSize = value; };
</script>

<script>
function TestDrive()
{
      var slowCar = new SlowCar(); // Safe and reliable, probably not fast
      var fasterCar = new FasterCar(); // Lacks air-bags, probably faster
      var protoCar = new PrototypeCar(); // Can technology win the day?

      var start = (new Date()).getTime();
      for(var i = 0; i < 100000; i++) { slowCar.SetTireSize(slowCar.GetTireSize() + 1); }
      var end = (new Date()).getTime();
      output.innerHTML += “Slow Car ” + (end – start) + “<br>”;
     

      start = (new Date()).getTime();
      for(var i = 0; i < 100000; i++) { fasterCar.m_tireSize += 1; }
      end = (new Date()).getTime();
      output.innerHTML += “Faster Car ” + (end – start) + “<br>”;

      start = (new Date()).getTime();
      for(var i = 0; i < 100000; i++) { protoCar.SetTireSize(protoCar.GetTireSize() + 1); }
      end = (new Date()).getTime();
      output.innerHTML += “Prototype Car ” + (end – start) + “<br>”;
}
</script>

<button onclick=”TestDrive();”>Test Drive Cars!</button>
<div id=”output”></div>

That’s all for Part 3.

Thanks,

Peter Gurevich
Program Manager

Justin Rogers
Software Development Engineer

Comments (70)

  1. Mark Wubben says:

    Is this really helping? I mean, most of the recommendations require drastic changes of code which makes it less readable. Sure, it may be faster, but the gains come at a steep price.

    Instead, I’d love to see tips on how to make IE render faster [1], or how to prevent it from slowing down if there’s a big application running for a longer time. These issues are causing the problems for developers, not function lookup.

    [1]: Actually, one way to do this is by giving elements with a lot of descendants layout.

  2. Will says:

    @Mark: Without data from a profiler to back you up, it’s not clear why you think these tips aren’t the best place to start optimizing.

    As for making the code unreadable, that’s a matter of opinion, but it’s hard to believe that the suggested code is any less readable.  As for how "drastic" the changes are, it entirely depends.  As with any perf optimization exercise, you should look for the bottlenecks (e.g. tight loops) and optimize those first.

  3. harry says:

    Hungarian variable notation is sooooo 1990!

    ugh!

  4. stuart says:

    Woah!… is the final example supposed to be the "good" one?

    If so, it bombed horribly… performance in IE7 is 4x worse that Firefox… Ouch!

  5. kkL says:

    The benchmark given shows a significant difference indeed (even in Opera!)

    However if all 300000 loops take 1-2 seconds, is there any practical use in this? Does anyone write scripts that are this heavy (and where bottleneck is not in network, DOM or rendering speed?)

  6. cyril says:

    I’m not agree with Mark, it’s just an habit. I use this syntax since many month and it’s great.

    For property I use getter and setter only if I need to make another action or if the property is public, if the property is internal I’ll use the direct access because there is no function call thus it’s a lot faster.

  7. steve_web says:

    @kkL

    The demo is to show that using object.property to get/set values is *MUCH* more optimized than creating your own getters/setters (regardless of how you create them, even prototyping)

    I think this is a "well duh" note for most of us, but it should stop those hoping to re-invent Java in JavaScript (in terms of OOP getters/setters)

    What I find funny, is stuart’s comment… he’s bang on.  It is very strange that such simple code execution is painfully slow in IE7, versus Firefox, or Opera.

  8. steve_web says:

    @cyril

    re: "or if the property is public"

    Are you referring to typical JavaScript here? if so, everything is Public!

    (yeah, there are ways to nest "private" members in JavaScript… but they weak at best, and any JavaScript guru worth his snuff can get access.)

  9. Dao says:

    function startDownload(url)

    {

         var source = new ActiveXObject("Ficitious.UrlFetcher");

         source.ondataready = function() { this.ondataready = null };

         source.startRequest(url);

    }

  10. Tino Zijdel says:

    Here we go again…

    "Currently the misuse of closures in connection with the IE DOM and various COM components are the number one cause of heightened memory usage within IE."

    The fact that IE has a serieus implementation issue with regards to DOM and COM doesn’t make the use of closures ‘misuse’.

    "source.ondataready = new function() { source.ondataready = null; }"

    ‘function’ is not a constructor, if you use the ‘new’ keyword here the function gets executed at parse-time. Furthermore this construct may suggest that IE supports expandos for ActiveX objects which is untrue.

    As for the ‘racing-cars': using getters and setters is normally a means to manipulate properties that are otherwise ‘private’ to the object instance – a feature that javascript does not really have but that can be mimiced by using (ironical in this context) closures:

    <script type="text/javascript">

    function foo()

    {

    var myPrivateVar = ‘foo';

    this.getMyPrivateVar = function()

    {

    return myPrivateVar;

    }

    this.setMyPrivateVar = function(value)

    {

    myPrivateVar = value;

    }

    }

    var myFoo = new foo();

    alert(myFoo.myPrivateVar); // undefined

    alert(myFoo.getMyPrivateVar()); // foo

    myFoo.setMyPrivateVar(‘bar’);

    alert(myFoo.getMyPrivateVar()); // bar

    </script>

    It is however pretty useless to use getters and setters for properties that are ‘public’ anyway and accessible directly as properties from the instance, it’s an abstraction that is completely unnecessary in javascript although some people tend to think that it is ‘purer’ (probably the same people that think that javascript should be more like *insert random programming language here*) – I disagree and it is well-known that such abstractions usually are only costly in terms of performance and are a recipe for leaks on a lower level.

    Even though the ‘Slow Car’ here outperforms the ‘Prototype Car’ the former cannot be considered good practice since it unnecessarily pollutes the global namespace (something IE already does on it’s own by hanging on to backwards-compatibility with the ancient and deprecated document.all object model). So even when you use only one instance of an object I’d still prefer to prototype object methods (or use anonymous functions as object properties) than use references to other global functions.

    I also still object to using the term ‘recommendations': these are merely tips or workarounds for problems in IE’s JScript implementation and (again) can in no way be considered ‘best programming practice’. If you don’t need the optimisation than please don’t use any of these techniques.

  11. Dao says:

    function PrototypeCar(){};

    PrototypeCar.prototype = {

         mTireSize: 17,

         mMaxSpeed: 250, // One can always dream!

         getTireSize: function() { return this.mTireSize; },

         setTireSize: function(value) { return this.mTireSize = value; }

    }

  12. Tino Zijdel says:

    Dao:

    "source.ondataready = function() { this.ondataready = null };"

    ‘this’ here will most likely be a reference to the global namespace and not to your object instance

    As for your last post with the PrototypeCar object; that’s merely a different notation for creating the same kind of object so it doesn’t matter in performance at all…

  13. Dao says:

    > I think this is a "well duh" note for most of us, but it should stop those hoping to re-invent Java in JavaScript (in terms of OOP getters/setters)

    JavaScript does have getters and setters, but JScript doesn’t.

    > (yeah, there are ways to nest "private" members in JavaScript… but they weak at best, and any JavaScript guru worth his snuff can get access.)

    In the strict sense, two objects have access to each others’ private properties and methods, if they are instances of the same class. That’s not even possible with JS 1.x.

  14. Dao says:

    > "source.ondataready = function() { this.ondataready = null };"

    > ‘this’ here will most likely be a reference to the global namespace and not to your object instance

    Not if you have a decent implementation of ECMAScript. But then again we’re talking about JScript + badly integrated ActiveX objects, so you could be right …

    > As for your last post with the PrototypeCar object; that’s merely a different notation for creating the same kind of object so it doesn’t matter in performance at all…

    I know, but it’s actually readable code. It doesn’t have to be ugly just because performance is our topic.

  15. lex says:

    Washington Post shows some scary stats for IE6 in 2006.

    http://blog.washingtonpost.com/securityfix/2007/01/internet_explorer_unsafe_for_2.html

    Does Microsoft expect that IE7 in 2007 will show a much better report card?

  16. Tino Zijdel says:

    "Not if you have a decent implementation of ECMAScript. But then again we’re talking about JScript + badly integrated ActiveX objects, so you could be right …"

    That totally depends on the implementation of those event-handlers within (in this case) the ActiveX object.

    In case of f.i. the onreadystatechange handler of an XMLHttpRequest object ‘this’ will refer to the function instance of the handler itself and not to the XMLHttpRequest instance object. Those things are simply beyond the ECMAScript scope…

    And to what is ‘readable’ or ‘ugly’ is basically a matter of taste. Mind that when you want to dynamically extend an object’s prototyped methods you’d still need to use "object.prototype.method = "

  17. Dave says:

    Tino is right about the closure issues. If IE’s implementation of things like XMLHTTP was truly native, it would be garbage-collected properly.

    "Without data from a profiler to back you up, it’s not clear why you think these tips aren’t the best place to start optimizing."

    Agreed! You should try the profiler in Firebug2, it is incredible. Between its ability to profile the code and its automatic profiling of page load times, you can pinpoint performance bottlenecks immediately. Honestly, in the first two days I had it running I was able to double the speed of some frequently-used code that I thought I had running pretty quickly.

    But back to IE7. Is there a good profiler/debugger for it yet? I can’t "see" the IE7 performance bottlenecks the way I can with Firebug and therefore can’t fix them. Articles like this, while nice, are not a realistic substitute for profiling your own code. I had already done the "platitude-based optimization" before I got the 2x performance increase using Firebug, so I know it’s not cutting the mustard.

  18. Bill Higgins says:

    > Currently the misuse of closures in

    > connection with the IE DOM and various COM

    > components are the number one cause of

    > heightened memory usage within IE.

    Dave, would you please provide some examples of what constitutes ‘misuse’ vs. ‘proper use’ of closures with the IE DOM and various COM components?

    For the examples of misuse, it would be interesting to know if the subsequent problems (e.g. heightened memory usage) are due to a misuse of the closure programming language concept or shortcomings of IE’s Javascript language implementation.

    http://billhiggins.us/weblog/

  19. Dao says:

    > That totally depends on the implementation of those event-handlers within (in this case) the ActiveX object.

    In the first place it’s a property called "ondataready" of the type "function". That’s well defined by ECMAScript.

    > In case of f.i. the onreadystatechange handler of an XMLHttpRequest object ‘this’ will refer to the function instance of the handler itself and not to the XMLHttpRequest instance object.

    I guess you mean IE7’s XMLHttpRequest, which of course is a wrapper for the ActiveX object. For every other browser, that behaviour would be considered a bug (or "compatibility with IE", but I doubt they do that).

  20. Dao says:

    > And to what is ‘readable’ or ‘ugly’ is basically a matter of taste. Mind that when you want to dynamically extend an object’s prototyped methods you’d still need to use "object.prototype.method = "

    Well, find me someone who prefers the structure of the initial code to mine. Mind that it wasn’t an extending scenario.

  21. Bill Higgins says:

    Oops, my question was addressed to Peter, not ‘Dave’ (long day).

    Also, it would be helpful if MS wrote more about their plans to address fundamental technical problems in IE (e.g. layout engine and Javascript implementation).

  22. Fduch says:

    goose, ehere are you?

    This entry really need your comment!

  23. PatriotB says:

    " If IE’s implementation of things like XMLHTTP was truly native, it would be garbage-collected properly"

    It depends what you mean by "native".  When discussing Windows (of which IE is part), "native" refers to C++/COM code, as opposed to scripting or managed code.

    I assume you mean native JScript/JavaScript/ECMAScript.  But why should this be the native language of the browser?  Should XMLHTTPRequest also have all language properties for VBScript, Perl, or any other pluggable scripting engine?

  24. Justin and Peter,

    Can you give us more info on changes in IE7 memory management? It appears that IE7 has made a big improvement in collecting circular references.  We certainly appreciate that.  I was wondering if IE7 still uses the terrible 100 slot/10,100 array slot addition criteria for triggering garbage collection that leads to O(n^2) GC over progressive object growth, or if the GC triggering algorithm has been improved.  I am pretty sure it is possible to acheive O(n) by simply making the threshold proportional to the current number of objects or memory or something… Maybe that has been done in IE7?

  25. Dao says:

    > I assume you mean native JScript/JavaScript/ECMAScript.  But why should this be the native language of the browser?

    Nobody says so. It’s just that C++ (or whatever) code needs to be glued properly with the scripting layer. All other browsers get this without being written in JavaScript.

    E.g. Firefox with XPConnect:

    >>> XMLHttpRequest.prototype.setRequestHeader

    function setRequestHeader() {

       [native code]

    }

    > Should XMLHTTPRequest also have all language properties for VBScript, Perl, or any other pluggable scripting engine?

    Yes.

  26. Tino Zijdel says:

    Dao: "In the first place it’s a property called "ondataready" of the type "function". That’s well defined by ECMAScript."

    sure, but the code that actually uses this property (fires is as an event for instance) that can determine in which scope it is executed. e.g. in javascript you can use call() or apply() to determine in which scope it is executed.

    "I guess you mean IE7’s XMLHttpRequest, which of course is a wrapper for the ActiveX object. For every other browser, that behaviour would be considered a bug (or "compatibility with IE", but I doubt they do that)."

    Well, I actually checked this in Firefox 😛

    My point being: ECMAScript doesn’t define the scope some function is executed in, the application itself does. Although it seems logical that ‘this’ within some object method would refer to the object instance this is not necessarily true.

    "Well, find me someone who prefers the structure of the initial code to mine. Mind that it wasn’t an extending scenario."

    I do prefer the object-notation actually, but I don’t think the alternative is ‘ugly’, only ‘less nice’ 😉

  27. Dao says:

    > but the code that actually uses this property (fires is as an event for instance) …

    It would actually work as expected if it was an event :) (as defined by the W3C XMLHttpRequest spec, btw.)

    As far as I remember, it isn’t, i.e. you can’t do xhr.attachEvent(‘onreadystatechange’…).

    > … that can determine in which scope it is executed. e.g. in javascript you can use call() or apply() to determine in which scope it is executed.

    Absolutely. It’s up to the implementation to do the right thing (which in this case isn’t defined by ECMAScript, yes). You can break any method with "var x = this.method; x()" or "(this.method)()". But I think it’s obvious that only applying it to the object itself makes sense. That’s also why I didn’t expect Firefox to follow the IE nonsense: I guess nobody uses "this" in onreadystatechange, because it’s really worthless — hence there’s no script that Firefox could have broken, if it called the method differently.

  28. Ken Cowan says:

    Peter Gurevich and Justin Rogers wrote an excellent on JScript performance in IE. This is the simplest,…

  29. Great article. You’ve really concentrated on the bottle necks like the time it takes to invoke a function and the time it takes to walk the prototype chain.

    Articles like this leads to more misunderstanding and bad coding practices.

  30. Aedrin says:

    @lex

    "Does Microsoft expect that IE7 in 2007 will show a much better report card?"

    Is this another one of those cases where people think something is true and fair because it’s in a newspaper/site?

    That article is nothing but media junk.

    Just because you can make a fancy diagram doesn’t make your statements true.

    There’s little information in there, just mostly opinion.

    Not to mention that the situations can’t be compared. (IE vs. FF)

  31. Matt Kruse says:

    Closures don’t cause memory leaks.

    Browsers that have garbage collection bugs (IE6) and continue to retain those bugs in new versions (IE7) cause memory leaks.

    Closures are an extremely powerful and useful programming technique. It’s unfortunate that you would recommend against their use simply because your browser has a bug that causes a memory leak.

    A huge amount of time has been spent by the js community to detect, resolve, and work around these IE memory leaks. It’s too bad this was required, and will continue to be required as long as MS refuses to fix the problem.

    Hopefully IE’s market share will continue to drop and we can begin to ignore these memory leaks because every other browser out there handles closures just fine.

  32. From my tests, IE7 has significantly improved GC.  Does any one know exactly what GC bugs were fixed and what remains in IE7?

    Of course you are correct, closures are a core part of JS, and recommending against them is essentially the same as recommending hacks. I would appreciate know what GC bug changes have been done for IE7 though. Anyone know?

  33. Adam van den Hoven says:

    Peter,

    While I can’t argue with some of what you wrote, it suffers from one major problem. Its absolutely wrong and lacks any value what so ever. I agree totally with Matt Kruse.

    But let’s look at what is being asserted in this article.

    First, the use of closures is not, as many have already suggested, a the sources of the problem. In fact, closures are one of the most useful techniques that are a available to a JavaScript programmer. Closures are exceedingly powerful. If you were to read Doug Crockford (cf. http://javascript.crockford.com/private.html and http://video.yahoo.com/?t=t&p=douglascrockford) you would quickly see that closures are indispensible.

    The problem is not with closures, but with using closures poorly and without considering the consequences of your code. So if you want to  improve your JavaScript code efficiency, then learn to use the language properly.

    In the second case, you suggest that the ues of setters and getters is a bad thing, and that we should refer to the bare members directly. But this is not necessarily true, or at least the second part isn’t necessarily true. Regardless of the language, having setters and getters that do nothing but set and get private variables should be a huge code stench. Generally we should be exposing behaviour NOT hiding data. So don’t write code that does myCar.setTireSize(myCar.getTireSize() + 1 ) or even myCare.tireSize ++ or which ever variation. Assuming its meaningful, you want something like myCar.incrementTireSize( 1 ).

    In reality, writing good code is more efficient than trying to work around browser problems. The root of all evils is optimizing too soon.

  34. vagelis says:

    For gods sake ppl, please fix your garbage collectors! It is a BIG trouble coding in IE!

  35. Matt Kruse says:

    >The problem is not with closures, but with

    >using closures poorly and without

    >considering the consequences of your code.

    There’s no such thing as "using closures poorly" with regards to this suggestion. Regardless of how they are used, they should not result in a memory leak.

    The only reason a person needs to "consider the consequences" of using closures is because IE’s garbage collection can’t break the circular reference between COM objects and javascript. It’s a fundamental flaw that has nothing to do with closures and everything to do with a broken garbage collector. In fact, the scenario can easily be created _without_ closures. It just happens that closures are convenient and extremely useful and they often end up exposing this flaw in IE. So of course, the easiest solution is to tell people not to expose the flaw!

    The really depressing thing is that MS acknowledged the bug years ago and actually actively decided not to fix it. Instead, we get "tips" like "avoid closures" that are really just thinly-disguised attempts by MS to CYA.

    Saying "avoid closures" is like saying "avoid using typeof". It’s a core feature of the language, and the only reason someone would recommend avoiding it is because their implementation of the feature is flawed. IMO.

  36. Thomas Daniels says:

    Just how difficult is it to write the <script> Element right? It must have a type-attribute including text/javascript.

    <script type="text/javascript">[…]</script>

    I’m sorry, but this is such a fundamental thing to know. I though you are good programmers. Why are you so far away from simple basics?

  37. Dao says:

    > It must have a type-attribute including text/javascript.

    application/javascript actually :)

    Of course IE doesn’t recognize that.

  38. Anne Onyme says:

    Please, stop the browser-bashing. This is a technical article, not a forum where script-kiddies make arrogant (and often irrevelant and/or wrong) comments and then playing the "Firefox/whatever is better" card.

    Please, grow up.

    Again, this is a technical article. If you feel you learn nothing, then go away, and let the professionals work and learn.

    1 – JS GC vs. COM RefCount

    AFAIK, the problem here is NOT the closure.

    It is mixing the JS GC and the COM Reference counting.

    For those smiling, COM is an important component of Windows, and it IS NOT strange to have objects like the DOM, the XMLHttpRequest to be COM objects (As are the FileSystem object, the WScript, the WshShell, etc.). If you are a Windows developper, then you’ll know why. And if you are not, then avoid commenting about choices you know nothing about…

    Note that Doug Crockford have a solution for some of the leaks problem of Internet Explorer:

    http://www.crockford.com/javascript/memory/leak.html

    I have not really tested it (even if I ran the test scripts with Fx2 and IE6), but it seems Ok (even if is appears quite "blunt") to me.

    So, as I understand it, this is not exactly a bug of IE (The same leak would exist in WScript, unless I’m wrong). It is a side effect from putting together a useful (if dangerous in a browser) Windows technology, and the JavaScript GC.

    Note that, though, that the Mozilla team had a similar problem (with their own XPCOM):

    http://www.mozilla.org/scriptable/avoiding-leaks.html

    https://bugzilla.mozilla.org/show_bug.cgi?id=283129

    And that it seems resolved since Firefox 1.5.

    2 – The properties VS Getter/Setter

    I agree with the solution, even if I would apply it only if every else failed. Accessing properties through getter/setter functions is better for the maintenance/evolution of the JS code.

    Now, I would NEVER consider the "create a global function MyObject__setThisValue and then, in the constructor, add this.setThisValue = MyObject__setThisValue" solution. This is polluting the global namespace, and we lose the interest of prototyping in JS.

    Conclusion

    I believe the dream of most web developpers for IE is to have things like a console, a debugger and a profiler. Sometimes, the performance issue can be corrected with a better algorithm (remember the 80/20 rule) or by pinpointing the bottleneck. This is something IE6 lacks, and AFAIK, IE7 lacks, too (Professionnaly, I don’t work anymore with Internet Explorer, even if I keep reading IE stuff…).

    I’m serious, there: When working on an Internet Explorer web application, I wrote, tested an debugged my code with Mozilla and then Firefox before trying it on IE! This is NOT normal (and no, Interdev is not a viable solution).

    So, IE Team, thank you for the article. I want more, so please keep giving us more insights of the internal workings of your browser. And this comes from a web developper using mostly Firefox, and quite ashamed by the childish behaviour of some people.

  39. Anne Onyme says:

    About the <script type="text/javascript"> issue Thomas Daniel and Dao "discovered". Your point is both incorrect and irrevelant:

    1 – You can use the meta

    <meta http-equiv="Content-Script-Type" content="text/javascript" />

    (or content="application/javascript" if you want) to mark the default script language of the HTML document, so in this case, the attribute type in the script element is NOT needed.

    2 – I’m surprised you saw the so-called missing type attribute, and yet, you missed that there is no <head>, <body> or even <html> element.

    Why?

    Because this is NOT an article about fully compliant and well formed X-HTML code. The point of this article is to explain a JScript issue. The fact the developer did not bloat the example code with optional attributes is of no interest here.

    And you both knew it, but wanted to bitch about a detail and play "Look at me, I am the expert here" instead of focusing on the real problem, that is, JScript performance and solutions. By the way, where are your own solutions? Thanks for your input, as your trolling helped no one here.

  40. kturcotte says:

    I just installed IE7 and one of the things that I noticed was that if I start IE7 with a command line specifying a file URI, it is not handled properly.

    For example:

    from the start menu select run an type

    "C:Program FilesInternet Exploreriexplore.exe" "file:///c:/IETest.html?a=4"

    This starts IE7 but the search portion of the uri is missing.

    For this to work you will need to create the file c:IEText.html that contains the following.

    <SCRIPT>

    document.write(window.location + "<br>" + window.location.search)

    </SCRIPT>

    This works correctly under IE6, and works correctly when you type the URI into the address bar, but the search portion of the URI is always lost when passed in from the command line.

    Any Thoughts?

  41. Dao says:

    > 1 – You can use […] <meta http-equiv="Content-Script-Type" content="text/javascript" />

    > […] to mark the default script language of the HTML document, so in this case, the

    > attribute type in the script element is NOT needed.

    Even if you’re the real expert, I daresay you are wrong.

    http://www.w3.org/TR/html4/interact/scripts.html#h-18.2.2.2

    > 2 – I’m surprised you saw the so-called missing type attribute, and yet, you missed that

    > there is no <head>, <body> or even <html> element. Why? Because this is NOT an article about

    > fully compliant and well formed X-HTML code.

    It was an excerpt. Thus it’s logical to leave out the rest of the document, but the type attribute is still missing. It’s XHTML, by the way.

    > And you both knew it, but wanted to bitch about a detail and play "Look at me, I am the expert

    > here" instead of focusing on the real problem, that is, JScript performance and solutions.

    > By the way, where are your own solutions? Thanks for your input, as your trolling helped no one here.

    Just too right, I didn’t write anything about scripting. I’m both a troll and a bad person in general. Feel better now that you exposed me?

    Anne, this could be the beginning of a beautiful friendship.

  42. Thomas Daniels says:

    > Of course IE doesn’t recognize that.

    Yeah. However JavaScript isn’t that strict about the MIME-Type. If you write text/javascript it’s ok. The server is to send the right Type. And that way IE recognises app/js or any of the newser ones.

    > 1 – You can use the meta

    <meta http-equiv="Content-Script-Type" content="text/javascript" />

    Actually you must use the meta anyway, it doesn’t make the type-attribute obolete. HTML-Spec states that type is a must, as well as the <meta> is in certain (most) circumstances.

    > 2 – I’m surprised you saw the so-called missing type attribute, and yet, you missed that there is no <head>, <body> or even <html> element.

    Oh noes, your doctype is missing..

    Right, this isn’t about HTML. However, the author decided to include the <script> element. If it’s in the examples the examples should be correct or else others will reproduce it the wrong way.

  43. Dao says:

    > If you write text/javascript it’s ok. The server is to send the right Type. And that way IE recognises app/js or any of the newser ones.

    Doesn’t it just ignore the header then?

  44. ash says:

    Anne,

    Very well said, I was wondering if anyone would point out the obvious incompatibility between GC and reference counting.  To expect Microsoft to re-write XMLHttpRequest as a native JS object just to appease a few die hard standards dudes (who will never be appeased anyway) is asking a bit much, particularly when they invented the thing in the first place.

    At a basic level ActiveX and COM are one and the same.  I’d just thought I’d drop that in because ActiveX has become such a dirty word and people often seem to confuse the two.

    It’s a pity the comments to the often excellent entries in this blog can’t be more constructive, instead of attempting to find fault in everything that is said.  We might all learn a lot more.  The MS IE engineers deserve more respect than this.

  45. Dao says:

    > To expect Microsoft to re-write XMLHttpRequest as a native JS object just to appease a few die hard standards dudes (who will never be appeased anyway) is asking a bit much

    Funny enough, it was this blog entry that pointed to the flaw in source.ondataready = new function() { source.ondataready = null; }: "This is an implicit circular reference, hard to spot, and IE leaks memory." Wouldn’t be a problem if you could use "this" inside of the method.

    And no, I don’t want MS to rewrite just XMLHttpRequest. I want MS to fix the underlying architectural flaws.

  46. Bill says:

    Anne I think you need to get a sense of humor, the  internet is community based if people want to bash microsoft now and again so what. Most people see through the sarcasm and ironies commonly posted. Usually when someone posts an inaccurate comment it is quickly corrected by other users. At the same time serious issues are raised which can only lead to a better internet explorer. Keep up the good work everyone.

  47. wil waals says:

    i still cannot open outlook express and pls send me detailed instructions,

    thanks.

  48. Bill Higgins says:

    Anne, I think that much of the frustration in the comments is not really directed at Peter but rather at the feeling that the IE team is addressing the symptoms (closures are problematic in IE) rather than the root causes of the problems (IE has serious technical issues w/ memory management).

    There’s a lot of bad will towards Microsoft because of the hiatus they took from major enhancements to the browser in the years between IE 6 and IE 7.

    I think what would really help community feelings towards Microsoft would be for posts like this to:

    1) acknowledge immediately offers advice geared towards IE problems, and not programming language problems (i.e. closures aren’t bad, but closures are dangerous in IE)

    2) point to a detailed technical roadmap where the IE team lays out (IN DETAIL) how they’ll be addressing the underlying technical problems in the next IE release

    We can assume that the IE team takes these underlying problems seriously, but until we see detailed plans published on the web, it’s a very bad feeling to see articles on how to workaround problems that have existed for over five years.

  49. lex says:

    @Aedrin

    Actually, yes, they are facts, they are backed up by public stats, none of it is heresay, and yes, you can most certainly compare browser A to browser B.

    Cold hard facts:

    1.) IE6 was vulnerable to open exploits for X days

    2.) Firefox was vulnerable to open exploits for Y days

    X vs. Y (You don’t even need to look at the website, to guess the correct answer!)

    What is scary, is the fact that the numbers are 10 times different. We’re not talking about IE6 being exposed for 2 to 3 more days, we’re talking about being exposed for over 75% of 2006.

    Cut that cake anyway you like it.. 25% secure, is *NOT* secure!

  50. Thomas Daniels says:

    > Doesn’t it just ignore the header then?

    Yeah. However, as said: JS isn’t as strict about the MIME-Type as CSS is. So it is ok, and needed as IE doesn’t understand die others. The attribute and the <meta> information are still required.

    > Anne I think you need to get a sense of humor, the  internet is community based if people want to bash microsoft now and again so what.

    No one *want’s* to bash MS. However, they’ve done questionable things in the past, other companies did that as well. Last time they were bashing Netscape, now it’s IE, next is unknown, but it’ll come.

    I’d like to love MS, however, the past has to be accepted first.

  51. John Thomas says:

    // Slow Car definition

    function SlowCar()

    {

         this.m_tireSize = 17;

         this.m_maxSpeed = 250;

         this.GetTireSize = SlowCar_get_tireSize;

         this.SetTireSize = SlowCar_put_tireSize;

    }

    function SlowCar_get_tireSize()

    {

         return this.m_tireSize;

    }

    function SlowCar_put_tireSize(value)

    {

         this.m_tireSize = value;

    }

    This is the way that I would could this class:

    function SlowCar(){

     var _tireSize = 17;

     var _maxSpeed = 250;

     this.getTireSize = function(){

       return _tireSize;

     }

     this.setTireSize = function(tireSize){

       if (typeof tireSize != "number")

         throw new Error("Invalid tire size…");

       _tireSize = parseInt(tireSize.toString());

     }

     this.getMaxSpeed = function(){

       return _maxSpeed;

     }

    }

    I use closures explicitly to implement private variables. I also usually do a lot more type checking when setting my private variables. Much easier to code and until I can find a profiler that works in IE, I will continue to use them.

    The jist of all these comments really must be to clearly and thorougly understand how to write JavaScript code. Performance can be increased tremendously if ALL functions and data were Global but then code would be a pain to maintain. Any object oriented code can be made more performant by ignoring the object orientation and just start calling functions directly. But I do agree that crtical use of indirection will generally speed up performance and yes…pre-mature optimization definitely is the root of all evil!

  52. Tino Zijdel says:

    Dao: you may be interested to know that your remarks about the scope of eventhandlers for javascript extension objects made me to write an article about it: http://therealcrisp.xs4all.nl/blog/2007/01/06/xmlhttprequest-and-the-scope-of-events/ 😉

  53. Aedrin says:

    @lex

    "Actually, yes, they are facts, they are backed up by public stats, none of it is heresay, and yes, you can most certainly compare browser A to browser B."

    Patch Available != Secure Users

    Like I’ve pointed out before, FireFox updates are sent out randomly at 1.5-2 month periods. IE updates are sent out at 1 month periods.

    Conclusion? The only real way to measure how safe each browser was, is to look at the releases of the full updates, not the patch itself.

    Then again, the whole discussion is silly anyway. As most security issues are in the user, not the browser.

  54. 三洋伺服 says:

    i still cannot open outlook express and pls send me detailed instructions

  55. terr0rist says:

    Well. Probably the article should have been named "Microsoft code inefficiencies"?

    For more than 5 years of programming JS, I formed an opinion that this &quot;browser&quot; ("MSIE") lacks just the following letters in its name: u,t,d. (Insert them where appropriate.)

    I don’t favor any browser since each has its own bugs, but bugs becoming standards is too much one can take.

    I hate the case when a programmer has to correct or avoid the bugs of the programming language he uses. It’s pretty much the same as driving a car without relying on its brake system.

    While microsoft will leave its bugs for a programmer to correct, I will continue to blame microsoft.

  56. cooperpx says:

    If you read this heated page, but only found the blog’s post useful … try watching Douglas Crawford’s seminars: "Theory of the DOM", and "Advanced Javascript".

    [ Douglas Crawford is the Javascript Architect for Yahoo, and quite enjoyable to watch ]

    http://video.yahoo.com/video/search?p=crockford&x=0&y=0

    Asside from the absurd notion to avoid closures… and I *do* mean absurd. He suggests to use a mature Javascript Library and let them resolve these issues (which cover leaks and performance).

    Additionally, he mentions that Javascript is a flexible, brilliant language. You can mold it to look and feel like whatever you want, but there’s a performance hit in doing so. Do it only if your code truely becomes more readable.

  57. cooperpx says:

    Ah damnit. Crawford != Crockford.

  58. Henk Tiggelaar says:

    Maybe rewriting the GC algorithm would prove to be a better solution than trying to convert every JavaScript programmer to the Microsoft way of coding.

    Just a thought…

  59. howa says:

    the js engine of IE is slow, and your team never think about rewrite the engine and tell us for these kind of optimizations (e.g. getter/setter)

    huh?

    does it make any sense?

  60. Peter Gurevich [MS] says:

    Sorry for the delay in response.  

    First of all let me thank you all for the great back and forth discussion.  It is great to see all that passion for Jscript and Jscript performance.

    I want to answer some of the questions you posed about our future plans and the exact nature of the changes we mad to our garbage collector.

    First of all, performance (and specifically Jscript performance) is a top priority for our next release and we will be spending a lot of time and effort to provide competitive or superior performance.  I cannot provide additional details beyond that but improving performance is solidly on our radar.

    Now as to the nature of the improvements we made to the garbage collection routine, here are the technical details.

    The garbage collector is the same general type as before – mark and sweep. Improvements have been made on the algorithm for determining when a garbage collection (GC) is triggered. The allocator keeps track of three classes of items: variables, array slots, and bytes of string space allocated through OLE Automation’s SysAlloc*String APIs. We call these triggers.

    In the old allocator: we do a GC on the next statement after any one of the following limits are passed since the previous GC:

    0x100 variables/temps/etc allocated

    0x1000 array slots allocated

    0x10000 bytes of strings allocated

    For applications that allocate large numbers of variables/objects/arrays to start up, a huge amount of time was spent performing a GC when only a very few objects were available for reclamation. For significant applications, there is a curve of memory usage during the apps lifetime. There is typically a lot of growth during startup and data loading, then the app reaches a steady state where the usage is fairly constant. Then at some point, the app is closed, and memory is released. For some apps this pattern repeats.

    In the new allocator, we apply a heuristic to guess when an application is growing and shrinking, and adapt the thresholds to the size of the application. We track the same items as before and bump the initial var and slot triggers:

    0x200 variables

    0x2000 slots

    0x10000 string bytes (same as before)

    We make the thresholds for vars and slots adaptive. Only the variable and slot triggers adapt (change thresholds). When a GC is triggered by passing one of these thresholds, we examine the total number of items and how many were actually reclaimed. When fewer than 15% of items are reclaimed, we guess that the application is growing, and we double the trigger (up to a maximum of 0x00010000). When more than 85% of items are reclaimed, we guess that the application is shrinking, and we reset the thresholds to the starting values.

    To keep an application’s memory usage in trim when running at steady state, every 10 seconds we trigger a GC  if the starting threshold of item have been allocated since the last collection. The timer-based collections do not cause the thresholds to change.

    For comparison, the CLR does a GC every 1 second. It can get away with this frequency because it is a generational GC, which reduces the cost of a collection pass. Because the jscript GC isn’t as efficient, we allow a longer time before triggering.

    I hope this helps and please let us know if you have any other questions.

    Thanks

    Peter Gurevich

  61. I’ve flagged a few links to noteworthy JavaScript posts over the last month. Yahoo! Video: Advanced…

  62. I’ve flagged a few links to noteworthy JavaScript posts over the last month. Yahoo! Video: Advanced JavaScript

  63. This is the first ever blog written by me in my entire life time. Let me take some time to introduce

  64. says:

    Peter Gurevich, Performance Programm Manager des IE7 Teams, hat seine dreiteilige Serie zu o.g. Thema

  65. Markus' Blog says:

    IE + JavaScript Performance Recommendations von Peter Gurevich, Programm Manager IE7 IE + JavaScript

  66. JavaScript est un langage " late binded " c’est à dire que chaque appel d’une propriété aura un coup

  67. JavaScript est un langage " late binded " c’est à dire que chaque appel d’une propriété aura un coût

  68. Recently someone asked me about the best practices for AJAX performance. Though this information is scattered