[CLOSED] Browser rendering lag.

Page 1 of 2 12 LastLast
  1. #1

    [CLOSED] Browser rendering lag.

    Hi,

    We have been facing a performance issue on our application where browser rendering is lagging for few seconds (5-12 sec).
    This is becoming very urgent on production environments. A lot of changes are being made on the solution (session state disabling, resource caching, source code optimization, asynchronous processing, etc.) with no luck.
    Please find attached a sample project that includes one view example of our application (few fieldsets where each one contains 1 to 8 ext.NET components).
    We noticed that when all fieldsets are collapsed, the rendering lag is reduced.
    We would like to change the components rendering mode from using "toscript()" method to "xRender" hoping that this could improve the application performance.
    The main objective is not to render all fieldsets at the same time (one shot) but one by one, this is why we are thinking of using xRender.
    We could also render empty fieldsets at the same time and then render their content using xRender.
    How could we accomplish this using xRender?

    The Ext.NET used version is 1.7
    I have exclued the ext.NET dll to avoid large attachment size.

    Thank you for your help,
    Last edited by Daniil; Oct 29, 2013 at 1:05 PM. Reason: [CLOSED]
  2. #2
    Hello,

    It would be best if you could post your code sample demonstrating how to reproduce the performance issue directly in a forum post. Please ensure you wrap your simplified code sample in [CODE] tags.
    Geoffrey McGill
    Founder
  3. #3
    Quote Originally Posted by geoffrey.mcgill View Post
    Hello,

    It would be best if you could post your code sample demonstrating how to reproduce the performance issue directly in a forum post. Please ensure you wrap your simplified code sample in [CODE] tags.
    Please find below the code sample.

    HomeController

    public class HomeController : Controller 
        {
            ToolbarGenerator toolBarGenerator = new ToolbarGenerator();
            FormGenerator formGenerator = new FormGenerator();
    
            public ActionResult Index()
            {
                return View();
            }
    
    
    
            public  ContentResult LoadPanelContent(String containerID)
            {
                ContentResult cr = new ContentResult();
                FormPanel form = formGenerator.CreateScreen();
                String script = formGenerator.CreateScreen().ToScript(
                    RenderMode.AddTo,
                    containerID);
                cr.Content = string.Format("<script>{0}</script>", script);
                return cr;
            }
    
    
            public ContentResult LoadMainItemToolBar(String containerID)
            {
                String script = toolBarGenerator.GenerateToolBar().ToScript(
                    RenderMode.AddTo,
                    containerID);
                ContentResult cr = new ContentResult();
                cr.Content = string.Format("<script>{0}</script>", script);
                return cr;
            }
    
    
            public AjaxStoreResult LoadStore()
            {
                AjaxStoreResult ajaxStoreResult = new AjaxStoreResult();
                DataTable data = GetStoreDataTable();
                ajaxStoreResult.Data = data;
                return ajaxStoreResult;
            }
    
            private DataTable GetStoreDataTable()
            {
                DataTable data = new DataTable();
                data.Columns.Add(new DataColumn("TEXT"));
                data.Columns.Add(new DataColumn("VALUE"));
                for (int i = 0; i < 40; i++)
                {
                    DataRow row = data.NewRow();
                    row[0] = "text " + i.ToString();
                    row[1] = i.ToString();
                    data.Rows.Add(row);
                }
                return data;
            }
    
        }
    ComboController

    public class ComboController : Controller
        {
            public AjaxStoreResult LoadStore()
            {
                AjaxStoreResult ajaxStoreResult = new AjaxStoreResult();
                DataTable data = GetStoreDataTable();
                ajaxStoreResult.Data = data;
                return ajaxStoreResult;
            }
    
            private DataTable GetStoreDataTable()
            {
                DataTable data = new DataTable();
                data.Columns.Add(new DataColumn("TEXT"));
                data.Columns.Add(new DataColumn("VALUE"));
                for (int i = 0; i < 40; i++)
                {
                    DataRow row = data.NewRow();
                    row[0] = "text " + i.ToString();
                    row[1] = i.ToString();
                    data.Rows.Add(row);
                }
                return data;
            }
           
        }
    FormGenerator Class

    public class FormGenerator
        {
            public FormGenerator() { }
    
    
    
            public FormPanel CreateScreen()
            {
                FormPanel formPanel = new FormPanel();
                formPanel.Border = false;
                formPanel.Padding = 10;
                formPanel.ID = "_screenform";
                formPanel.ButtonAlign = Alignment.Center;
                #region FormPanel Content Generation
                for (int i = 0; i < 8; i++)
                {
                    formPanel.Items.Add(GenerateFieldset());
                }
                #endregion
                return formPanel;
            }
    
            private FieldSet GenerateFieldset()
            {
                #region Fieldset
                FieldSet fieldSet = new FieldSet();
                fieldSet.AutoDoLayout = true;
                fieldSet.AutoHeight = true;
                fieldSet.LabelWidth = 150;
                fieldSet.Layout = "HBoxLayout";
                HBoxLayoutConfig hbLayout = new HBoxLayoutConfig();
                hbLayout.Align = HBoxAlign.StretchMax;
                hbLayout.Padding = "5";
                fieldSet.LayoutConfig.Add(hbLayout);
                fieldSet.Title = "fieldSet";
                #endregion
                #region Panels
                Panel panelLeft = new Panel();
                panelLeft.Border = false;
                panelLeft.Layout = "FormLayout";
                panelLeft.Flex = 1;
                panelLeft.AutoHeight = true;
                Panel panelRight = new Panel();
                panelRight.Border = false;
                panelRight.Layout = "FormLayout";
                panelRight.AutoHeight = true;
                panelRight.Flex = 1;
                #endregion
                for (int i = 0; i < 12; i++)
                {
                    int r;
                    Math.DivRem(i, 2, out r);
                    if (r == 0)
                    {
                        panelRight.Items.Add(GenerateTextField(i));
                    }
                    else
                    {
                        panelLeft.Items.Add(GenerateComboBox(i));
                    }
                }
                fieldSet.Items.Add(panelLeft);
                fieldSet.Items.Add(panelRight);
                return fieldSet;
    
            }
    
            private Panel GenerateTextField(int i)
            {
                Panel panel = new Panel();
                panel.Border = false;
                panel.Padding = 0;
                panel.Layout = "Anchor";
                TextField text = new TextField();
                text.LabelAlign = LabelAlign.Right;
                text.AnchorHorizontal = "85%";
                text.LabelSeparator = " ";
                text.FieldLabel = "Text Field " + i.ToString();
                var tip = new ToolTip();
                tip.Html = "Help text Field " + i.ToString();
                text.ToolTips.Add(tip);
                panel.Items.Add(text);
                return panel;
            }
    
            private Panel GenerateComboBox(int i)
            {
                Panel panel = new Panel();
                panel.Border = false;
                panel.Padding = 0;
                panel.Layout = "FormLayout";
                panel.LabelAlign = LabelAlign.Right;
                var combobox = new ComboBox();
                combobox.LabelAlign = LabelAlign.Right;
                combobox.MinListWidth = 150;
                combobox.AnchorHorizontal = "85%";
                combobox.LabelSeparator = " ";
                combobox.DisplayField = "TEXT";
                combobox.ValueField = "VALUE";
                combobox.TypeAhead = false;
                combobox.ForceSelection = true;
                combobox.Mode = DataLoadMode.Single;
                combobox.EnableKeyEvents = true;
                combobox.FieldLabel = "Combo " + i.ToString();
                var store = new Store();
                #region Http Proxy
                HttpProxy httpProxy = new HttpProxy();
                int r;
                Math.DivRem(i/2, 2, out r);
                if (r == 0)
                {
                    httpProxy.Url = "/Home/LoadStore/";
                }
                else { httpProxy.Url = "/Combo/LoadStore/"; }
    
                store.Proxy.Add(httpProxy);
                #endregion
                #region JSON Reader
                var reader = new JsonReader();
                reader.Root = "data";
                reader.TotalProperty = "total";
                reader.IDProperty = "VALUE";
                var field1 = new RecordField();
                field1.Name = "TEXT";
                var field2 = new RecordField();
                field2.Name = "VALUE";
                reader.Fields.Add(field2);
                reader.Fields.Add(field1);
                store.Reader.Add(reader);
                store.AutoLoad = true;
                #endregion
                combobox.Store.Add(store);
                var tip = new ToolTip();
                tip.Html = "Help Combo " + i.ToString();
                combobox.ToolTips.Add(tip);
                panel.Items.Add(combobox);
                return panel;
            }
    
        }
    ToolbarGenerator class

    public class ToolbarGenerator
        {
            public ToolbarGenerator()
            {
    
            }
    
            public Toolbar GenerateToolBar()
            {
                Toolbar toolBar = new Toolbar();
                ToolbarFill toolBarFill = new ToolbarFill();
                Button saveButton = new Button();
                saveButton.ID = "_saveBTN";
                saveButton.Icon = Icon.Disk;
                saveButton.StandOut = true;
                saveButton.Flex = 1;
                saveButton.Text = "Save";
                toolBar.Items.Add(saveButton);
                Button scanBtn = new Button();
                scanBtn.StandOut = true;
                scanBtn.Flex = 1;
                scanBtn.Text = "Scan";
                scanBtn.Icon = Icon.TabBlue;
                toolBar.Items.Add(scanBtn);
                Button comButton = new Button();
                comButton.Text = "Com";
                comButton.StandOut = true;
                comButton.Icon = Icon.Comments;
                toolBar.Items.Add(comButton);
                toolBar.Items.Add(toolBarFill);
                Button refreshButton = new Button();
                refreshButton.Text = "Refresh";
                refreshButton.StandOut = true;
                refreshButton.Icon = Icon.PageRefresh;
                refreshButton.Listeners.Click.Handler = "location.reload();";
                toolBar.Items.Add(refreshButton);
                return toolBar;
            }
        }
    View: Index.aspx

    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
    
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    <!DOCTYPE html>
    <html>
    <head id="Head1" runat="server">
    </head>
    <body>
        <ext:ResourceManager ID="ResourceManager1" runat="server" SubmitDisabled="false">
            <Listeners>
            </Listeners>
        </ext:ResourceManager>
        <form id="Form1" runat="server">
        </form>
        <ext:Viewport ID="Viewport1" runat="server" Layout="BorderLayout" AutoScroll="false">
            <Items>
                <ext:Panel runat="server" ID="_toolBar" Region="North" Height="30" Border="false">
                    <AutoLoad Url="/Home/LoadMainItemToolBar" NoCache="true">
                        <Params>
                            <ext:Parameter Name="containerID" Value="#{_toolBar}" Mode="Value" />
                        </Params>
                    </AutoLoad>
                </ext:Panel>
                <ext:Panel ID="_pnlitemDetails" runat="server" Border="false" Header="false" AutoScroll="true"
                    Region="Center">
                     <AutoLoad Url="/Home/LoadPanelContent" NoCache="true"  Scripts="true">
                        <Params>
                            <ext:Parameter Name="containerID" Value="#{_pnlitemDetails}" Mode="Value" />
                        </Params>
                    </AutoLoad>
                </ext:Panel>
            </Items>
            <Content>
            </Content>
        </ext:Viewport>
        <script type="text/javascript">
            /*@cc_on
            @*/   
        </script>
        <script src="../../Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
    </body>
    </html>
    Thank you in advance.
  4. #4
    Hi,

    Thank you for the test case.

    I tested it in IE9, FireFox and Chrome. It renders in about 2-3 seconds. So, I cannot reproduce a 5-12 seconds lag.

    I have a few questions/suggestions.

    1. Do you really need AutoLoad true for the Stores?

    2. Do you really need an individual Store for each ComboBox?

    3. Do you really need this setting?
    fieldSet.AutoDoLayout = true;
    I think you can remove it. It can slow down the things.

    4. Please use a Container instead of a Panel anywhere where possible. For example:
    Panel panelLeft = new Panel();
    =>
    Container panelLeft = new Container();
    The same with the panelRight.

    5. I see kind of overnesting. Do you really need to wrap ComboBoxes and TextFields in additional Panels? If change those methods to:
    private TextField GenerateTextField(int i) 
    {
        ...
        return text;
    }
    and
    private ComboBox GenerateComboBox(int i)
    {
        ...
        return  combobox;
    }
    it would give the benefit in performance, but the view seems to look the same.
    Last edited by Daniil; Oct 18, 2013 at 4:10 AM.
  5. #5
    Hi,

    Thank you for your quick and details answers, questions and suggestions

    I tested it in IE9, FireFox and Chrome. It renders in about 2-3 seconds. So, I cannot reproduce a 5-12 seconds lag.
    From our side, tests are done on IE8, FireFox and Chrome. indeed, you will not be able to reproduce the 5-12 lag as the real solution is much more sophisticated(more components on the same form including gridS).
    Meanwhile, 2-3 seconds to render this sample is quite slow too.

    1. Do you really need AutoLoad true for the Stores?
    Good point. In the real solution AutoLoad is not used ofter and mainly, Store are loaded after render.

    2. Do you really need an individual Store for each ComboBox?
    Yes. We absolutely need a different Store for each combobox. For this sample we used the same content for all combobox to avoid complicated project. But, in our application Combobox Stores are loaded from XML files or Database.

    3. Do you really need this setting?
    
    fieldSet.AutoDoLayout = true;
    Well well this is quite complicated to explain. We have a JS generator based on customizable conditions. When one of these conditions is true, some fieldsets are hidden or shown. these actions (E.g show hidden fieldset) bungle the fieldset appearance (height of components under the fieldset becomes very small). The only solution that fixed this issue, was to set AutoDoLayout.

    4. Please use a Container instead of a Panel anywhere where possible. For example:
    
    Panel panelLeft = new Panel();
    =>
    
    Container panelLeft = new Container();
    Ok we will. But actually, we did this few months ago and we didn't notice any rendering performance improvement.

    5. I see kind of overnesting. Do you really need to wrap ComboBoxes and TextFields in additional Panels?
    Ok.

    -------------------------------
    These changes may have a huge impact on the application architecture and will cost us a lot of time.
    As performance improvement is really urgent, we are thinking of temporary (intermediate) solution while these suggestions can take place (maybe including a migration to Ext.NET 2).
    One of the test case was to render all fieldset collapsed and this hugely reduces the rendering lag. This is why we would like to either render fieldsets one by one or render them collapsed and then expand them one by one on the client side (after render or another event).

    I hope this give you more clarification about the whole context and what we are really facing.
    Last edited by Daly_AF; Oct 18, 2013 at 10:33 AM.
  6. #6
    Hello!

    In my opinion, the best solution in your case is to render all the FieldSets collapsed and render their items when it's necessary. Does it applicable for your case? Even rendering using XRender will cause the same perfomance issues, especially in IE8.

    About migration to 2.x, it's better to do if you want to continue the development of this application and this will give you better performance and options for rendering and optimization, especially in MVC. But you are about to finish the development of this application it's better to stick with 1.x because it requires some time to implement the migration.
    Last edited by geoffrey.mcgill; Oct 18, 2013 at 9:21 PM.
  7. #7
    There is a good chance that you don't get the improvement in performance after migration to v2. At least, as big as you might expect. Especially, in IE8. There were cases when the developers got worse performance in legacy browsers after migration.

    Regarding your description, we think that the main problem is the fact that too many components are rendered initially on bootstrap and some overnesting of containers. So, we would suggest to focus on that.

    Rendering the FieldSets collapsed looks a good solution. If you face any problem implementing it, please ask our assistance. We would be glad to help.
    Last edited by Daniil; Oct 21, 2013 at 5:00 AM.
  8. #8
    Hi,

    Thank you for your valuable suggestions.
    Actually, we are thinking of 2 solutions/ways to improve the rendering performance and we will choose one of them based on the time cost and rendering impact.

    1st solution:
    Render all fieldsets collapsed and expand them from the client side one after one.

    2nd solution:
    Render empty fieldsets and then render their contents using "AutoLoad".

    Considering that "after render" (OnDocumentReady), we have JavaScript processing that hide, show, disabled, etc. components depending on values of other components, using solution (2) JS did not work on all components with no erros raised.

    We started implementing solution (1) which we hope will improve rendering performance.

    If you have more suggestions, they will be very appreciated.
    We will keep you posted.
  9. #9
    Quote Originally Posted by Daly_AF View Post
    1st solution:
    Render all fieldsets collapsed and expand them from the client side one after one.

    2nd solution:
    Render empty fieldsets and then render their contents using "AutoLoad".
    Do you mean that a FieldSet's content should be rendered/loaded on a user action?

    Quote Originally Posted by Daly_AF View Post
    Considering that "after render" (OnDocumentReady), we have JavaScript processing that hide, show, disabled, etc. components depending on values of other components, using solution (2) JS did not work on all components with no erros raised.
    Generally speaking, DocumentReady is not an "after render" event. It doesn't mean all the components are rendered. Hard to say why "JS did not work" without a test case.

    By the way, here is another suggestion for improving the performance. It is much better to configure a component before rendering if possible.

    For example, configuring a component with
    disabled: true
    is better than calling
    component.disable();
    after rendering.

    A disable call is a JavaScript function call and it operates with DOM. Dealing with DOM is always one of bottle necks.

    Here is many tips to improve performance.
    http://www.sencha.com/forum/showthre...Best-Practices
  10. #10
    Do you mean that a FieldSet's content should be rendered/loaded on a user action?
    No user actions are required.
    Solution (1) is based on rendering all fieldsets collapsed and then expand them one by one with no user action.
    Soluton (2) is based on rendering empty fieldsets and then load their content with autoload and no user action is needed too.


    Generally speaking, DocumentReady is not an "after render" event. It doesn't mean all the components are rendered. Hard to say why "JS did not work" without a test case.
    Indeed, DocumentReady in not an "after render" event. What I wanted to say is that a JS is executed when content result is returned by a controller action. In our case, it is executed after render.

    By the way, here is another suggestion for improving the performance. It is much better to configure a component before rendering if possible.

    For example, configuring a component with
    disabled: true
    is better than calling
    component.disable();
    after rendering.

    A disable call is a JavaScript function call and it operates with DOM. Dealing with DOM is always one of bottle necks.
    Ok got it. But actually, the JS executed after render (and not on DocumentReady) is customizable (E.g. the user can for instance configure to hide TextField 1 when Combobox2 value = 1. Disabled DateField3 when TextField5 = 'hour' ....). This is why components are configured as much as possible before rendering and then the executed JS after render is customizable and depends on custom business rules.

    Thank you.
Page 1 of 2 12 LastLast

Similar Threads

  1. [CLOSED] Browser compatibility
    By ATLAS in forum 2.x Legacy Premium Help
    Replies: 1
    Last Post: Oct 10, 2013, 12:52 PM
  2. [CLOSED] Nepture Theme rendering issue on IE8 Browser
    By kevinhwang in forum 2.x Legacy Premium Help
    Replies: 7
    Last Post: Sep 30, 2013, 5:22 PM
  3. [CLOSED] Browser detection
    By Pyropace in forum 2.x Legacy Premium Help
    Replies: 2
    Last Post: Mar 29, 2013, 4:11 AM
  4. [CLOSED] Useful Browser Extensions/Plugins
    By cwolcott in forum Open Discussions
    Replies: 4
    Last Post: Mar 25, 2013, 8:37 AM
  5. [CLOSED] Browser issue
    By Tarun_Chand in forum 2.x Legacy Premium Help
    Replies: 1
    Last Post: Mar 25, 2013, 2:59 AM

Posting Permissions