Miłosz Orzeł

.net, js, html, arduino, java... no rants or clickbaits.

Debug oraz Release a wydajność kodu korzystającego z Microsoft AJAX Framework

Istnieje kilka powodów, dla których nie powinno się umieszczać aplikacji ASP.NET w środowisku produkcyjnym z ustawieniem <compilation debug=”true”/> (czytaj…). Wbrew pozorom prędkość wykonywania instrukcji kodu po stronie serwera nie stanowi bardzo istotnego problemu. Inaczej jednak wygląda sytuacja po stronie klienta - gdy nasza aplikacja korzysta z javascriptowej biblioteki Microsoft AJAX Framework. Wówczas ustawienie Release/Debug* ma ogromny wpływ na szybkość wykonywania kodu aplikacji!

Doskonale widać to na przykładzie poniższej pętli, korzystającej z funkcji startsWith dostarczanej wraz z częścią kliencką pakietu ASP.NET AJAX.

for (var i = 0; i < 10000; i++) {
    'xxx'.startsWith('abc');
}

Pętla ta wykonuje się ok. 5 razy wolniej gdy używana jest wersja debug biblioteki JavaScript!  Czasy gdy JS był używany do wyświetlania alertów dawno minęły. Teraz gdy aplikacje webowe mogą posiadać tysiące linii kodu wykonywanego po stronie klienta, tak wielka różnica wydajnościowa może być sporym problemem (zwłaszcza gdy przeglądarka zgłosi komunikat o wolnym działaniu skryptu na stronie).

Skąd bierze się różnica w szybkości działania? Wynika ona z tego, że kod JavaScript opracowany przez Microsoft dla potrzeb tworzenia aplikacji ajaxowych, dostarczany jest w dwóch wersjach. Wersja, która jest wykorzystywana w trybie Debug, zawiera bloki kodu znacznie ułatwiające rozwijanie aplikacji – np. sprawdzają one ilość i typy parametrów podawanych w wywołaniu funkcji. Wersja dostarczana do przeglądarki w trybie Release nie zawiera tego rodzaju udogodnień – przez co skrypt wykonuje znacznie mniej pracy i działa szybciej.

Oto kod wykonywany przy wywołaniu metody startsWith w trybie Release (w celu ograniczenia wielkości plików pobieranych przez przeglądarkę kod nie zawiera komentarzy i zbędnych białych znaków):

String.prototype.startsWith=function(a){return this.substr(0,a.length)===a};

A to kod z trybu Debug:

String.prototype.startsWith = function String$startsWith(prefix) {
    /// <summary locid="M:J#String.startsWith" />
    /// <param name="prefix"></param>
    /// <returns type="Boolean"></returns>
    var e = Function._validateParams(arguments, [{
        name: "prefix",
        type: String
    }]);

    if (e) throw e;

    return (this.substr(0, prefix.length) === prefix);
}

Widzisz wywołanie funkcji _validateParams? Korzysta ona z kilku innych funkcji – łącznie kod walidujący parametry ma 155 linii (w wersji 3.5.30729.196 pliku MicrosoftAjax.debug.js).

Function._validateParams = function Function$_validateParams(params, expectedParams) {
    var e;
    e = Function._validateParameterCount(params, expectedParams);

    if (e) {
        e.popStackFrame();
        return e;
    }

    for (var i = 0; i < params.length; i++) {
        var expectedParam = expectedParams[Math.min(i, expectedParams.length - 1)];
        var paramName = expectedParam.name;

        if (expectedParam.parameterArray) {
            paramName += "[" + (i - expectedParams.length + 1) + "]";
        }

        e = Function._validateParameter(params[i], expectedParam, paramName);

        if (e) {
            e.popStackFrame();

            return e;
        }
    }

    return null;
* Domyślnie, to jaka wersja biblioteki JavaScript ASP.NET AJAX zostanie użyta, zależy od ustawienia atrybutu debug w elemencie configuration/system.web/compilation w pliku Web.config. Tryb emisji skryptów można jednak zmienić ustawiając atrybut ScriptMode kontrolki ScriptManager na Release lub Debug. Ustawienie to ma wyższy priorytet niż ustawienie w konfiguracji aplikacji.