Julian Jelfs’ Blog

Interrupted XmlHttpRequests cause IE to hang

Posted in Javascript by julianjelfs on May 6, 2009

I ran into a problem using MS Ajax script services recently. I was getting reports of intermittent hanging in IE (6 and 7) with some newly developed pages. I had a vague feeling it was something to do with the Script Services and a quick search revealed that this is a relatively well known problem.

As described in one of the responses to that question, the issues is caused when a page closes after an asynchronous ajax request is started but before it completes. In this scenario one of the browser’s available connections (of which it has 2 by default) is tied up and not released. So if this happens a couple of times, the browser has no available connections to service normal requests and appears to hang.

The solution is to abort any pending XmlHttpRequest when the page unloads. It’s not totally obvious how to do this when you are using Script Services with the generated proxy, because the actual XmlHttpRequest object itself is buried in multiple layers of magic. After a bit of digging I came up with the following solution:

$(function(){
    var pending = null;
    Sys.Net.WebRequestManager.add_invokingRequest(function(executor, args){
        pending = args.get_webRequest().get_executor();
    });

    Sys.Net.WebRequestManager.add_completedRequest(function(executor, args){
        pending = null;
    });

    $(window).unload(function(){
        if(pending!==null){
            pending.abort();
        }
    });
});

So what this does is just track the executor of the currently executing web request and set it to null when the request completes. On unload, we check if there are any pending request executors, and if there are we call abort on them. This prevents the hanging issue for me in IE which is a big relief.

Obviously this mechanism may not be adequate for you if ajax calls are not queued because there may be more than one pending request. In my case, all service calls are channelled through a queue so that can’t happen. Otherwise you would have to implement some mechanism to correlate the invoked request with the completed request.

Tagged with: ,

Digging into YUICompressor – fo sho!

Posted in Javascript by julianjelfs on April 8, 2009

I was looking into using the YUI Compressor code to compress and combine my javascript files and specifically at the ready made msbuild task that comes with it. I wandered why the “ObfuscateJavascript” parameter appeared not to work using the following build script fragment:

<CompressorTask
            JavaScriptFiles="@(JavaScriptFiles)"
            ObfuscateJavaScript="True"
            PreserveAllSemicolons="False"
            DisableOptimizations="False"
            EncodingType="Default"
            DeleteJavaScriptFiles="False"
            LineBreakPosition="-1"
            JavaScriptOutputFile="$(UserInterfaceReleaseDir)\include\ControlScripts\ArmControlContainer.js"
            LoggingType="ALittleBit"
            ThreadCulture="en-gb" />

Digging into the code a little I can see this:

_obfuscateJavaScript = !string.IsNullOrEmpty(ObfuscateJavaScript)
    && ParseSillyTrueFalseValue(ObfuscateJavaScript.ToUpperInvariant());

ParseSillyTrueFalseValue? Well it looks like this:

private static bool ParseSillyTrueFalseValue(string value)
{
    bool result;

    if (string.IsNullOrEmpty(value))
    {
        throw new ArgumentNullException("value");
    }

    switch (value)
    {
        case "yes":
        case "y":
        case "yep":
        case "yeah":
        case "true":
        case "fosho":
        case "fo sho":
            result = true;
            break;
        default:
            result = false;
            break;
    }

    return result;
}

How bizarre? And also notice that the input is always being converted to upper case, but the switch statement only checks lower case values so it always returns false.

I’m sure that the compression code itself is a lot more solid but I think I might write my own msbuild task….

Tagged with:

Shrinking select lists in IE – jQuery.append bug?

Posted in jQuery by julianjelfs on March 27, 2009

I encountered a problem recently where I noticed that select lists with width set to 100% were mysteriously shrinking on me and I could only resolve the issue by setting a pixel width. This was a serious inconvenience since I have a fluid layout which is more or less ruined if I am forced to use fixed pixel widths. I found that others had noticed this issue here and here but there was no solution.

I set up a test with the following markup:

<div style=”width:300px”>

<select id=”shrinky” style=”width:100%”>

<option>One</option>

<option>Two</option>

<option>Three</option>

<option>Four</option>

<option>Five</option>

</select>

</div>


I also found, on closer examination that this seems to be a problem with using jQuery append in IE as demonstrated by the following test:

tf.AddTest(“Shrinking select list – demonstrates jquery bug”, function(test){

test.Expects(1);

var sel = $j(“#shrinky”);

var width = sel.width();

sel.append(“<option>test</option>”);

test.NotEqual(width, sel.width());

});

To show that this appears to be a problem with jQuery we can achieve the same thing manipulating the DOM manually and show that the select lists width does not change. This is demonstrated by a second test (notice the assertion at the end is flipped showing that the width is unchanged this time):

tf.AddTest(“Shrinking select list – native”, function(test){

test.Expects(1);

var sel = $j(“#shrinky”);

var width = sel.width();

var optn = document.createElement(“OPTION”);

optn.text = “test”;

sel[0].options.add(optn);

test.Equal(width, sel.width());

});

This alternative approach “solves” the problem for me in that I can still have 100% width select lists so my layout is not ruined. If I get the chance I am going to look into the way jQuery.append works to see if there is any obvious way to patch it so this alternative approach can become unnecessary.

Tagged with: ,

Javascript string concatenation performance

Posted in Javascript by julianjelfs on March 27, 2009

I was recently profiling some javascript code and began to suspect that the Microsoft Ajax.Net type extension String.format was causing some quite noticeable performance issue so I decided to run some tests to get to the bottom of it. The results were quite surprising.

Test 1 was normal string concatenation:

tf.AddTest(“StringConcat”, function(test){

test.Expects(1);

var start = new Date();

for(var j=0; j<10000; j++){

var str = “hello” + 1 + “hello” + 2 + “hello” + 3 + “hello” + 4 + “hello” + 5;

}

var end = new Date();

alert(end.getTime()-start.getTime());

test.Pass();

});

Test 2 was using the MS type extension:

tf.AddTest(“StringFormat”, function(test){

test.Expects(1);

var start = new Date();

for(var j=0; j<10000; j++){

var str = String.format(“hello{0}hello{1}hello{2}hello{3}hello{4}”, 1,2,3,4,5);

}

var end = new Date();

alert(end.getTime()-start.getTime());

test.Pass();

});

Test 3 was using a home made imitation of the MS type extension using regular expressions to fill in the blanks in the tokenised string:

tf.AddTest(“HomemadeFormat”, function(test){

test.Expects(1);

var start = new Date();

for(var j=0; j<10000; j++){

var str = format(“hello{0}hello{1}hello{2}hello{3}hello{4}”, 1,2,3,4,5);

}

var end = new Date();

alert(end.getTime()-start.getTime());

test.Pass();

});


where format is just a local function (which could easily be attached to the String prototype) defined as follows:

var format = function(tokenised) {

var args = arguments;

return tokenised.replace(/{[0-9]+}/g, function(matched) {

return args[parseInt(matched.replace(/[{}]/g, “”))+1];

});

}

Results for IE 7:
Test 1 : 328 milliseconds
Test 2 : 18626 milliseconds
Test 3 : 860 milliseconds

Results for Firefox 3.0.7:
Test 1 : 1 milliseconds
Test 2 : 6697 milliseconds
Test 3 : 431 milliseconds

Results for Google Chrome:
Test 1 : 8 milliseconds
Test 2 : 1958 milliseconds
Test 3 : 263 milliseconds

So, this is not particularly scientific and doing string concatenation in tight loops is not very realistic etc etc but a few things are pretty clear here. Firstly, simple string concatenation is by far the best approach. Secondly, IE performs a lot worse than the others with any approach. And thirdly, MS Ajax String.Format is a great deal worse than the homemade equivalent. Makes me wander what the other MS Ajax.Net script extensions are like …

Tagged with: ,