QCubed object creation js performance

JavaScript performance comparison

Test case created

Info

this function is called for every qcubed control, it adds function to every dom node representing a qcubed control ...

Preparation code

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<span id="editButton1_ctl"><button type="button" name="editButton" id="editButton1" class="button"> Edit Person </button></span>

<span id="editButton2_ctl"><button type="button" name="editButton" id="editButton2" class="button"> Edit Person </button></span>

<span id="editButton3_ctl"><button type="button" name="editButton" id="editButton3" class="button"> Edit Person </button></span>

<span id="editButton4_ctl"><button type="button" name="editButton" id="editButton4" class="button"> Edit Person </button></span>

<span id="editButton5_ctl"><button type="button" name="editButton" id="editButton5" class="button"> Edit Person </button></span>

<span id="editButton6_ctl"><button type="button" name="editButton" id="editButton6" class="button"> Edit Person </button></span>

<span id="editButton7_ctl"><button type="button" name="editButton" id="editButton17" class="button"> Edit Person </button></span>

<span id="editButton8_ctl"><button type="button" name="editButton" id="editButton8" class="button"> Edit Person </button></span>

<span id="editButton9_ctl"><button type="button" name="editButton" id="editButton9" class="button"> Edit Person </button></span>

<span id="editButton10_ctl"><button type="button" name="editButton" id="editButton10" class="button"> Edit Person </button></span>

<span id="editButton11_ctl"><button type="button" name="editButton" id="editButton11" class="button"> Edit Person </button></span>

<span id="editButton12_ctl"><button type="button" name="editButton" id="editButton12" class="button"> Edit Person </button></span>

<span id="editButton13_ctl"><button type="button" name="editButton" id="editButton13" class="button"> Edit Person </button></span>

<span id="editButton14_ctl"><button type="button" name="editButton" id="editButton14" class="button"> Edit Person </button></span>

<span id="editButton15_ctl"><button type="button" name="editButton" id="editButton15" class="button"> Edit Person </button></span>

<span id="editButton16_ctl"><button type="button" name="editButton" id="editButton16" class="button"> Edit Person </button></span>

<span id="editButton17_ctl"><button type="button" name="editButton" id="editButton17" class="button"> Edit Person </button></span>

<span id="editButton18_ctl"><button type="button" name="editButton" id="editButton18" class="button"> Edit Person </button></span>

<span id="editButton19_ctl"><button type="button" name="editButton" id="editButton19" class="button"> Edit Person </button></span>

<span id="editButton20_ctl"><button type="button" name="editButton" id="editButton20" class="button"> Edit Person </button></span>

<script>
var $j = jQuery.noConflict();

$j.fn.extend({
        wait: function(time, type) {
                time = time || 1000;
                type = type || "fx";
                return this.queue(type, function() {
                        var self = this;
                        setTimeout(function() {
                                $j(self).dequeue();
                        }, time);
                });
        }
});

/*
 * Queued Ajax requests.
 * A new Ajax request won't be started until the previous queued
 * request has finished.
 */

$j.ajaxQueue = function(o){
         $j.ajax( o );
};


/*
 * Synced Ajax requests.
 * The Ajax request will happen as soon as you call this method, but
 * the callbacks (success/error/complete) won't fire until all previous
 * synced requests have been completed.
 */

$j.ajaxSync = function(o){
        var fn = $j.ajaxSync.fn, data = $j.ajaxSync.data, pos = fn.length;

        fn[ pos ] = {
                error: o.error,
                success: o.success,
                complete: o.complete,
                done: false
        };

        data[ pos ] = {
                error: [],
                success: [],
                complete: []
        };

        o.error = function(){ data[ pos ].error = arguments; };
        o.success = function(){ data[ pos ].success = arguments; };
        o.complete = function(){
                data[ pos ].complete = arguments;
                fn[ pos ].done = true;

                if ( pos == 0 || !fn[ pos-1 ] )
                        for ( var i = pos; i < fn.length && fn[i].done; i++ ) {
                                if ( fn[i].error ) fn[i].error.apply( $j, data[i].error );
                                if ( fn[i].success ) fn[i].success.apply( $j, data[i].success );
                                if ( fn[i].complete ) fn[i].complete.apply( $j, data[i].complete );

                                fn[i] = null;
                                data[i] = null;
                        }
        };

        return $j.ajax(o);
};

$j.ajaxSync.fn = [];
$j.ajaxSync.data = [];

///////////////////////////////////////////////////
// The QCubed Object is used for everything in Qcodo
///////////////////////////////////////////////////
        var qcubed = {

                recordControlModification: function (strControlId, strProperty, strNewValue) {
                        if (!qcubed.controlModifications[strControlId])
                                qcubed.controlModifications[strControlId] = new Object;
                        qcubed.controlModifications[strControlId][strProperty] = strNewValue;
                },

                postBack: function(strForm, strControl, strEvent, mixParameter) {
                        var strForm = $j("#Qform__FormId").attr("value");
                        var objForm = $j('#' + strForm);
                       
                        if ( mixParameter && ( typeof mixParameter !== "string" ) ) {
                                mixParameter = $j.param( { "Qform__FormParameter" : mixParameter } );
                                objForm.append('<input type="hidden" name="Qform__FormParameterType" value="obj">');
                        }
                       
                        $j('#Qform__FormControl').attr("value", strControl);
                        $j('#Qform__FormEvent').attr("value", strEvent);
                        $j('#Qform__FormParameter').attr("value", mixParameter);
                        $j('#Qform__FormCallType').attr("value", "Server");
                        $j('#Qform__FormUpdates').attr("value", this.formUpdates());
                        $j('#Qform__FormCheckableControls').attr("value", this.formCheckableControls(strForm, "Server"));
                       
                        // have $j trigger the submit event (so it can catch all submit events)
                        objForm.trigger("submit");
                },

                formUpdates: function() {
                        var strToReturn = "";
                        for (var strControlId in qcubed.controlModifications)
                                for (var strProperty in qcubed.controlModifications[strControlId])
                                        strToReturn += strControlId + " " + strProperty + " " + qcubed.controlModifications[strControlId][strProperty] + "\n";
                        qcubed.controlModifications = new Object;
                        return strToReturn;
                },

                formCheckableControls: function(strForm, strCallType) {

                        // Select the QCubed Form
                        var objFormElements = $j('#' + strForm + ' input,select,textarea');
                        var strToReturn = "";

                        objFormElements.each(function(i) {
                                if ((($j(this).attr("type") == "checkbox") ||
                                         ($j(this).attr("type") == "radio")) &&
                                        ((strCallType == "Ajax") ||
                                        (!$j(this).attr("disabled")))) {

                                        var strControlId = $j(this).attr("id");

                                        // CheckBoxList
                                        if (strControlId.indexOf('[') >= 0) {
                                                if (strControlId.indexOf('[0]') >= 0)
                                                        strToReturn += " " + strControlId.substring(0, strControlId.length - 3);
                                        // RadioButtonList
                                        } else if (strControlId.indexOf('_') >= 0) {
                                                if (strControlId.indexOf('_0') >= 0)
                                                        strToReturn += " " + strControlId.substring(0, strControlId.length - 2);

                                        // Standard Radio or Checkbox
                                        } else {
                                                strToReturn += " " + strControlId;
                                        }
                                }
                        });

                        if (strToReturn.length > 0)
                                return strToReturn.substring(1);
                        else
                                return "";
                },
               
                postAjax: function(strForm, strControl, strEvent, mixParameter, strWaitIconControlId) {

                        var objForm = $j('#' + strForm);
                        var strFormAction = objForm.attr("action");
                        var objFormElements = $j('#' + strForm + ' input,#' + strForm + ' select,#' + strForm + ' textarea');
                        var strPostData = '';
                       
                        if( mixParameter && ( typeof mixParameter !== "string" ) ) {
                                strPostData = $j.param( { "Qform__FormParameter" : mixParameter } );
                                objFormElements = objFormElements.not("#Qform__FormParameter");
                        }
                        else {
                                $j('#Qform__FormParameter').attr("value", mixParameter);
                        }
                       
                        $j('#Qform__FormControl').attr("value", strControl);
                        $j('#Qform__FormEvent').attr("value", strEvent);       
                        $j('#Qform__FormCallType').attr("value", "Ajax");
                        $j('#Qform__FormUpdates').attr("value", this.formUpdates());
                        $j('#Qform__FormCheckableControls').attr("value", this.formCheckableControls(strForm, "Ajax"));
                                       
                        objFormElements.each(function () {
                                var strType = $j(this).attr("type");
                                var strControlId = $j(this).attr("id");
                                switch (strType) {
                                        case "checkbox":
                                        case "radio":
                                                if ($j(this).attr("checked")) {
                                                        var strTestName = $j(this).attr("name") + "_";
                                                        if (strControlId.substring(0, strTestName.length) == strTestName)
                                                                strPostData += "&" + $j(this).attr("name") + "=" + strControlId.substring(strTestName.length);
                                                        else
                                                                strPostData += "&" + strControlId + "=" + $j(this).val();
                                                };
                                                break;

                                        case "select-multiple":
                                                var blnOneSelected = false;
                                                $j(this).find(':selected').each (function (i) {
                                                        strPostData += "&" + $j(this).parents("select").attr("name") + "=";
                                                        strPostData += $j(this).val();
                                                });
                                                break;

                                        default:
                                                strPostData += "&" + strControlId + "=";

                                                // For Internationalization -- we must escape the element's value properly
                                                var strPostValue = $j(this).val();
                                                if (strPostValue) {
                                                        strPostValue = strPostValue.replace(/\%/g, "%25");
                                                        strPostValue = strPostValue.replace(/&/g, escape('&'));
                                                        strPostValue = strPostValue.replace(/\+/g, "%2B");
                                                }
                                                strPostData += strPostValue;
                                                break;
                                }
                        });

                        if (strWaitIconControlId) {
                                this.objAjaxWaitIcon = this.getWrapper(strWaitIconControlId);
                                if (this.objAjaxWaitIcon)
                                        this.objAjaxWaitIcon.style.display = 'inline';
                        };
                        $j.ajaxQueue({
                                url: strFormAction,
                                type: "POST",
                                data: strPostData,
                                error: function (XMLHttpRequest, textStatus, errorThrown) {
                                        if (XMLHttpRequest.status != 0 || XMLHttpRequest.responseText.length > 0) {
                                                alert("An error occurred during AJAX Response parsing.\r\n\r\nThe error response will appear in a new popup.");
                                                var objErrorWindow = window.open('about:blank', 'qcodo_error','menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=1000,height=700,left=50,top=50');
                                                objErrorWindow.focus();
                                                objErrorWindow.document.write(XMLHttpRequest.responseText);
                                                return;
                                        }
                                },
                                success: function (xml) {
                                        $j(xml).find('control').each(function() {
                                                var strControlId = '#' + $j(this).attr("id");
                                                var strControlHtml = $j(this).text();

                                                if (strControlId == "#Qform__FormState") {
                                                        $j(strControlId).val(strControlHtml);
                                                } else {
                                                        var ctrl = $j(strControlId + "_ctl");
                                                        if(ctrl.length)
                                                                ctrl.html(strControlHtml);
                                                        else
                                                                $j(strControlId).replaceWith(strControlHtml);
                                                }
                                        });
                                        var strCommand = '';
                                        $j(xml).find('command').each(function() {
                                                strCommand += $j(this).text();
                                        });
                                        eval(strCommand);
                                        if (qcubed.objAjaxWaitIcon)
                                                qcubed.objAjaxWaitIcon.style.display = 'none';
                                }
                        });

                },

                initialize: function() {



                ////////////////////////////////
                // Browser-related functionality
                ////////////////////////////////

                        this.loadJavaScriptFile = function(strScript, objCallback) {
                                strScript = qc.jsAssets + "/" + strScript;
                                jQuery.ajax({type: "GET",url: strScript,success: objCallback,dataType: "script",cache: true});//$j.getScript(strScript, objCallback);
                        };

                        this.loadStyleSheetFile = function(strStyleSheetFile, strMediaType) {
                                strStyleSheetFile = qc.cssAssets + "/" + strStyleSheetFile;

                                $j('head').append('<link rel="stylesheet" href="' + strStyleSheetFile + '" type="text/css" />');

                        };




                /////////////////////////////
                // QForm-related functionality
                /////////////////////////////

                        this.wrappers = new Array();


                }
        };

        ///////////////////////////////
        // Timers-related functionality
        ///////////////////////////////

                qcubed._objTimers = new Object();

                qcubed.clearTimeout = function(strTimerId) {
                        if (qcubed._objTimers[strTimerId]) {
                                clearTimeout(qcubed._objTimers[strTimerId]);
                                qcubed._objTimers[strTimerId] = null;
                        };
                };

                qcubed.setTimeout = function(strTimerId, strAction, intDelay) {
                        qcubed.clearTimeout(strTimerId);
                        qcubed._objTimers[strTimerId] = setTimeout(strAction, intDelay);
                };



        /////////////////////////////////////
        // Event Object-related functionality
        /////////////////////////////////////

                // You may still use this function but be advised
                // we no longer use it in core.  All event terminations
                // and event bubbling are handled through jQuery.
                // see http://trac.qcu.be/projects/qcubed/ticket/681
                // @deprecated
                qcubed.terminateEvent = function(objEvent) {
                        objEvent = qcubed.handleEvent(objEvent);

                        if (objEvent) {
                                // Stop Propogation
                                if (objEvent.preventDefault)
                                        objEvent.preventDefault();
                                if (objEvent.stopPropagation)
                                        objEvent.stopPropagation();
                                objEvent.cancelBubble = true;
                                objEvent.returnValue = false;
                        };

                        return false;
                };


////////////////////////////////
// Qcodo Shortcut and Initialize
////////////////////////////////
        // Make sure we set $j.noConflict() to $j

        var qc = qcubed;
        qc.initialize();

        qc.pB = qcubed.postBack;
        qc.pA = qcubed.postAjax;

</script>


<script>
/////////////////////////////////
// Controls-related functionality
/////////////////////////////////

        qcubed.getControl = function(mixControl) {
                if (typeof(mixControl) == 'string')
                        return document.getElementById(mixControl);
                else
                        return mixControl;
        };

        qcubed.getWrapper = function(mixControl) {
                var objControl;
                if (!(objControl = qcubed.getControl(mixControl)))
                {
            //maybe it doesn't have a child control, just the wrapper
                        if (typeof(mixControl) == 'string')
                        return this.getControl(mixControl + "_ctl");

                    return;
                }

                if (objControl)
                        return this.getControl(objControl.id + "_ctl");
                else
                        return null;
        };



/////////////////////////////
// Register Control - General
/////////////////////////////

        qcubed.controlModifications = new Object;
        qcubed.javascriptStyleToQcodo = new Object;
        qcubed.javascriptStyleToQcodo["backgroundColor"] = "BackColor";
        qcubed.javascriptStyleToQcodo["borderColor"] = "BorderColor";
        qcubed.javascriptStyleToQcodo["borderStyle"] = "BorderStyle";
        qcubed.javascriptStyleToQcodo["border"] = "BorderWidth";
        qcubed.javascriptStyleToQcodo["height"] = "Height";
        qcubed.javascriptStyleToQcodo["width"] = "Width";
        qcubed.javascriptStyleToQcodo["text"] = "Text";

        qcubed.javascriptWrapperStyleToQcodo = new Object;
        qcubed.javascriptWrapperStyleToQcodo["position"] = "Position";
        qcubed.javascriptWrapperStyleToQcodo["top"] = "Top";
        qcubed.javascriptWrapperStyleToQcodo["left"] = "Left";

        qcubed.recordControlModification = function(strControlId, strProperty, strNewValue) {
                if (!qcubed.controlModifications[strControlId])
                        qcubed.controlModifications[strControlId] = new Object;
                qcubed.controlModifications[strControlId][strProperty] = strNewValue;
        };

        qcubed.registerControl = function(mixControl) {
                var objControl;
                objControl = qcubed.getControl(mixControl);

                // Link the Wrapper and the Control together
                var objWrapper = this.getWrapper(mixControl);
                if(!objWrapper) return;

            if(objControl !== null)
                objControl.wrapper = objWrapper;

                objWrapper.control = objControl;

                // Add the wrapper to the global qcodo wrappers array
                qcubed.wrappers[objWrapper.id] = objWrapper;


                // Create New Methods, etc.
                // Like: objWrapper.something = xyz;

                // Updating Style-related Things
                objWrapper.updateStyle = function(strStyleName, strNewValue) {
                    if(this.control === null)
                    {
                            switch (strStyleName) {
                                    case "display":
                                            if (strNewValue) {
                                                    objWrapper.style.display = "inline";
                                            } else {
                                                    objWrapper.style.display = "none";
                                            };
                                            break;
                                    default:
                                            if (qcubed.javascriptWrapperStyleToQcodo[strStyleName]) {
                                                    this.style[strStyleName] = strNewValue;
                                            };
                                            break;
                            };
                    return;
                    }

                        var objControl = this.control;

                        switch (strStyleName) {
                                case "className":
                                        objControl.className = strNewValue;
                                        qcubed.recordControlModification(objControl.id, "CssClass", strNewValue);
                                        break;

                                case "parent":
                                        if (strNewValue) {
                                                var objNewParentControl = qcubed.getControl(strNewValue);
                                                objNewParentControl.appendChild(this);
                                                qcubed.recordControlModification(objControl.id, "Parent", strNewValue);
                                        } else {
                                                var objParentControl = this.parentNode;
                                                objParentControl.removeChild(this);
                                                qcubed.recordControlModification(objControl.id, "Parent", "");
                                        };
                                        break;

                                case "displayStyle":
                                        objControl.style.display = strNewValue;
                                        qcubed.recordControlModification(objControl.id, "DisplayStyle", strNewValue);
                                        break;

                                case "display":
                                        if (strNewValue) {
                                                objWrapper.style.display = "inline";
                                                qcubed.recordControlModification(objControl.id, "Display", "1");
                                        } else {
                                                objWrapper.style.display = "none";
                                                qcubed.recordControlModification(objControl.id, "Display", "0");
                                        };
                                        break;

                                case "enabled":
                                        if (strNewValue) {
                                                objWrapper.control.disabled = false;
                                                qcubed.recordControlModification(objControl.id, "Enabled", "1");
                                        } else {
                                                objWrapper.control.disabled = true;
                                                qcubed.recordControlModification(objControl.id, "Enabled", "0");
                                        };
                                        break;

                                case "width":
                                case "height":
                                        objControl.style[strStyleName] = strNewValue;
                                        if (qcubed.javascriptStyleToQcodo[strStyleName])
                                                qcubed.recordControlModification(objControl.id, qcubed.javascriptStyleToQcodo[strStyleName], strNewValue);
                                        if (objWrapper.handle)
                                                objWrapper.updateHandle();
                                        break;

                                case "text":
                                        objControl.innerHTML = strNewValue;
                                        qcubed.recordControlModification(objControl.id, "Text", strNewValue);
                                        break;

                                default:
                                        if (qcubed.javascriptWrapperStyleToQcodo[strStyleName]) {
                                                this.style[strStyleName] = strNewValue;
                                                qcubed.recordControlModification(objControl.id, qcubed.javascriptWrapperStyleToQcodo[strStyleName], strNewValue);
                                        } else {
                                                objControl.style[strStyleName] = strNewValue;
                                                if (qcubed.javascriptStyleToQcodo[strStyleName])
                                                        qcubed.recordControlModification(objControl.id, qcubed.javascriptStyleToQcodo[strStyleName], strNewValue);
                                        };
                                        break;
                        };
                };

                // Positioning-related functions

                objWrapper.getAbsolutePosition = function() {
                        var intOffsetLeft = 0;
                        var intOffsetTop = 0;

                        var objControl = this.control;

                        while (objControl) {
                                // If we are IE, we don't want to include calculating
                                // controls who's wrappers are position:relative
                                if ((objControl.wrapper) && (objControl.wrapper.style.position == "relative")) {

                                } else {
                                        intOffsetLeft += objControl.offsetLeft;
                                        intOffsetTop += objControl.offsetTop;
                                };
                                objControl = objControl.offsetParent;
                        };

                        return {x:intOffsetLeft, y:intOffsetTop};
                };

                objWrapper.setAbsolutePosition = function(intNewX, intNewY, blnBindToParent) {
                        var objControl = this.offsetParent;

                        while (objControl) {
                                intNewX -= objControl.offsetLeft;
                                intNewY -= objControl.offsetTop;
                                objControl = objControl.offsetParent;
                        };

                        if (blnBindToParent) {
                                if (this.parentNode.nodeName.toLowerCase() != 'form') {
                                        // intNewX and intNewY must be within the parent's control
                                        intNewX = Math.max(intNewX, 0);
                                        intNewY = Math.max(intNewY, 0);

                                        intNewX = Math.min(intNewX, this.offsetParent.offsetWidth - this.offsetWidth);
                                        intNewY = Math.min(intNewY, this.offsetParent.offsetHeight - this.offsetHeight);
                                };
                        };

                        this.updateStyle("left", intNewX + "px");
                        this.updateStyle("top", intNewY + "px");
                };

                // Toggle Display / Enabled
                objWrapper.toggleDisplay = function(strShowOrHide) {
                        // Toggles the display/hiding of the entire control (including any design/wrapper HTML)
                        // If ShowOrHide is blank, then we toggle
                        // Otherwise, we'll execute a "show" or a "hide"
                        if (strShowOrHide) {
                                if (strShowOrHide == "show")
                                        this.updateStyle("display", true);
                                else
                                        this.updateStyle("display", false);
                        } else
                                this.updateStyle("display", (this.style.display == "none") ? true : false);
                };

                objWrapper.toggleEnabled = function(strEnableOrDisable) {
                        if (strEnableOrDisable) {
                                if (strEnableOrDisable == "enable")
                                        this.updateStyle("enabled", true);
                                else
                                        this.updateStyle("enabled", false);
                        } else
                                this.updateStyle("enabled", (this.control.disabled) ? true : false);
                };

                objWrapper.registerClickPosition = function(objEvent) {
                        var intX = objEvent.pageX - this.control.offsetLeft;
                        var intY = objEvent.pageY - this.control.offsetTop;

                        $j('#' + this.control.id + "_x").val(intX);
                        $j('#' + this.control.id + "_y").val(intY);
                };

                // Focus
                objWrapper.focus = function() {
                        $j('#' + this.control.id).focus();
                };

                // Select All (will only work for textboxes only)
                objWrapper.select = function() {
                        $j('#' + this.control.id).select();
                };

                // Blink
                objWrapper.blink = function(strFromColor, strToColor) {
                        $j('#' + this.control.id).css('background-color', '' + strFromColor);
                        $j('#' + this.control.id).animate({ backgroundColor: '' + strToColor }, 500)
                };
        }

        qcubed.registerControlArray = function(mixControlArray) {
                var intLength = mixControlArray.length;
                for (var intIndex = 0; intIndex < intLength; intIndex++)
                        qcubed.registerControl(mixControlArray[intIndex]);
        };



//////////////////
// Qcodo Shortcuts
//////////////////

        qc.getC = qcubed.getControl;
        qc.getW = qcubed.getWrapper;
        qc.regC = qcubed.registerControl;
        qc.regCA = qcubed.registerControlArray;

qcubed.altRegisterControl = function(mixControl) {
                var objControl;
                objControl = qcubed.getControl(mixControl);

                // Link the Wrapper and the Control together
                var objWrapper = this.getWrapper(mixControl);
                if(!objWrapper) return;

            if(objControl !== null)
                objControl.wrapper = objWrapper;

            objWrapper.control = objControl;
}
</script>
 

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
default qcubed behaviour
for(i = 1;i<=20;i++) {
   qcubed.registerControl("editButton" + i);
}
pending…
version that does not create functions on each QControl dom node
for(i = 1;i<=20;i++) {
   qcubed.altRegisterControl("editButton" + i);
}
pending…

You can edit these tests or add even more tests to this page by appending /edit to the URL.

Compare results of other browsers

0 comments

Add a comment