2

我有一个页面,它在网格中按字母对联系人进行分组。对于我较大的联系人集(1000-1500),网格加载速度慢得令人难以忍受(分钟)。但是,浏览器几乎被锁定,所以人们认为它已经崩溃了。

根据 chrome profiler,我 91% 的时间都花在了我最近最大的敌人 .InnerHTML() 上。

据我所知,在填写联系人可观察对象时,我不会发送不必要的通知。

我试图在这个 jsFiddle 中将页面提炼成一个简单的形式。

http://jsfiddle.net/DCLaR/105/ (感谢 Ryan Rahlf 修复此问题)

看起来简单的版本还可以,所以混合中肯定有其他东西。

我将继续发布我的整页 html,即使它有点乱。

从实际页面代码的小提琴开始,不退出运行,可能太复杂而无法填充:http: //jsfiddle.net/DCLaR/108/

也许有人可以发现某些东西或已知会导致性能问题的东西。

我看到了这个类似的问题,但没有从中得到解决方案。

的HTML

<button id="btnSaveOrg" data-bind="click: $root.SaveAll">Save All</button><span data-bind="html: SaveStatus"></span>
    <table class="orgTable">
        <tr>
            <td>
                <ul id="orgList" data-bind="template: { name: 'orgChartTemplate', foreach: DepartmentHierarchy }" style="display:none"></ul>

                <div id="orgChart2" class="orgChart"></div>
            </td>
            <td data-bind="with: SelectedDepartment">
                 <div class="departmentContainer">
                      <span class="departmentTitle" data-bind="text: DepartmentName" ></span>
                        <div class="buttonBar">
                            <a title="Edit Department" data-bind="click: $root.BeginEdit, visible: $root.InDisplayMode">
                                <img src="/Images/iconEdit.png" alt="Edit" />
                            </a>
                            <a title="Add Department" data-bind="click: $root.BeginAdd, visible: $root.InDisplayMode">
                                <img src="/Images/iconAdd.png" alt="Add" />
                            </a>
                        </div> 


                        <div class="departmentInnerContainer">

                            <div id="departmentTabs" data-bind="kendoTabStrip: {}">
                                <ul>
                                    <li class="k-state-active" data-bind="visible: IsRoot">All Company Contacts</li>
                                    <li class="k-state-active" data-bind="visible: IsNotRoot">Department Contacts</li>
                                    <li data-bind="visible: IsNotRoot">Associate Contacts</li>
                                </ul>
                                <div id="allContacts">
                                      <div class="buttonBar">
                                          Find: <input type="text" data-bind="value: $root.CurrentDepartmentContacts.SearchStringText" /><a data-bind="    click: $root.CurrentDepartmentContacts.Search"><img src="/Images/iconSearch.png" /></a>
                                      </div>
                                    <div data-bind="template: { name: 'ContactListTemplate', foreach: $root.CurrentDepartmentContacts }"></div>
                                </div>
                                <div id="currentContacts">
                                      <div class="buttonBar">
                                          Find: <input type="text" data-bind="value: $root.CurrentDepartmentContacts.SearchStringText" /><a data-bind="    click: $root.CurrentDepartmentContacts.Search"><img src="/Images/iconSearch.png" /></a>
                                      </div>
                                    <div data-bind="template: { name: 'ContactListTemplate', foreach: $root.CurrentDepartmentContacts }"></div>
                                </div>
                                <div id="assocContacts">
                                    <div>
                                         <input type="checkbox" data-bind="checked: $root.ShowAssociatedContacts" /> Show Contacts tied to departments<br />
                                      <input data-bind="value: $root.ContactSearchText" /><a data-bind="click: $root.SearchAllContacts "><img src="/Images/iconSearch.png" /></a>  

                                        <br />

                                      <button data-bind="click: $root.CheckAllContacts">Check All</button> <button data-bind="click: $root.UncheckAllContacts">Uncheck All</button>
                                    </div>
                                    <!-- ko if: $root.AllContactsSearchResult().length>0 -->
                                    <div  class="contactsContainerOrg" data-bind="foreach: $root.AllContactsSearchResult">
                                        <div>
                                                <input type="checkbox" data-bind="checked: IsChecked" /><span data-bind="html: ContactName"></span>
                                        </div>
                                    </div>
                                    <!-- /ko -->
                                    <!-- ko if: $root.AllContactsSearchResult().length==0 -->
                                    <div  class="contactsContainerOrg">
                                        <div>
                                             No Contacts Found
                                        </div>
                                    </div>
                                    <!-- /ko -->
                                    <button data-bind="click: $root.AssociateSelectedContacts, enable: $root.AssociatedContactsChecked">Associate Contacts</button>
                                </div>
                            </div>
                      </div>
                        </div> 
            </td>
        </tr>

    </table>

    <div id="divAddEditDepartment" style="display:none">
        <span data-bind="template: { name: 'editDeptTemplate', foreach: EditingDepartment }"></span>
    </div>


<script type="text/html" id="OldDept">
     <div class="departmentContainer">
                       <button id="Button1" data-bind="click: $root.AddDepartment, visible: $root.InDisplayMode">Add Department</button>

                       <fieldset class="departmentFieldSet">
                           <legend>Selcted Department</legend>

                             <span data-bind="template: { name: 'viewDeptTemplate', foreach: SelectedDepartment }, visible: InDisplayMode"></span>
                             <span data-bind="template: { name: 'editDeptTemplate', foreach: SelectedDepartment }, visible: InEditMode"></span><br /><br />


                              <b>Contacts</b><br />

                              Search: <input type="text" data-bind="value: $root.ContactsVM.SearchString" /><br />
                              <div data-bind="template: { name: 'ContactListTemplate', foreach: $root.ContactsVM }"></div>
                        </fieldset>
                  </div> 

    </script>


    <asp:HiddenField ID="hdnCustomerId" Value="7" runat="server"/>

    <!-- Tempaltes -->
    <script type="text/html" id="orgChartTemplate">
        <li data-bind="attr: { DeptId: CustomerDepartmentId }">
            <div  class="innerNode" data-bind="css: { selectedNode: IsSelected }">
                <img src="/Images/Contacts/CompanyOrg.png" /><span style="font-weight:bold;display:block" data-bind="html: DepartmentName"></span> <br /><br /> 
            </div>

            <ul data-bind="template: { name: 'orgChartTemplateChild', foreach: Children }"></ul>
        </li>
    </script>

 <script type="text/html" id="orgChartTemplateChild">
        <li data-bind="attr: { DeptId: CustomerDepartmentId }">
            <div  class="innerNode" data-bind="css: { selectedNode: IsSelected }">
                <span style="font-weight:bold" data-bind="html: DepartmentName"></span> <br /><br /> 

                <span data-bind="html: ContactCountDisplay"></span>
            </div>

            <ul data-bind="template: { name: 'orgChartTemplateChild', foreach: Children }"></ul>
        </li>
    </script>

    <script type="text/html" id="viewDeptTemplate">

        <div class="noWrap"> <label>Department Name:</label><div style="width: 12px; display: inline-block;" /><span data-bind="text: DepartmentName"></span></div> <br />
        <span data-bind="visible: $root.IsNew">
          <span class="noWrap">   <label>Parent Department:</label><span style="width: 5px; display: inline-block;"/><span data-bind="text: ParentDepartmentName"> </span></span>
        </span> 
        <br /><br />
        <button data-bind="click: $root.BeginEdit">Edit</button>

    </script>

    <%--Edit template markup--%>
    <script type="text/html" id="editDeptTemplate" >
       <div class="noWrap"> <label>Department Name:</label><div style="width: 12px; display: inline-block;" /><input type="text" data-bind="value: DepartmentName" required="required"> <span id="reqDepartmentError" style="color: red; display: none;">*</span></div><br />
        <div class="noWrap"><label>Parent Department:</label><div style="width: 5px; display: inline-block;"/><select data-bind="options: $root.GetParentCustomerDepartmentOptions(), optionsText: 'DepartmentName', optionsValue: 'CustomerDepartmentId', value: ParentCustomerDepartmentId" ></select></div><br />
    </script>

    <script type="text/html" id="ContactListTemplate">
        <div id="Div1" class="contactsContainerOrg" data-bind="foreach: ContactGroups">
            <div class="contactGroupHeader" data-bind="text: GroupName, attr: { groupName: GroupName }"></div>
            <div class="contactGroupContainer">
                <div data-bind="template: { name: $root.GetContactTemplate, foreach: Contacts }">
                </div>
            </div>
        </div>

        <div data-bind="if: ShowGroupBy">
            <span data-bind="foreach: AllLetterContactGroups">
                <span class="groupList" data-bind="text: GroupName, click: $root.ScrollToGroup, style: { fontWeight: HasContacts() ? '900' : '300', fontSize: HasContacts() ? '12px' : '10px' }"></span>&nbsp;
            </span>
        </div>
    </script>

   <script type="text/html" id="ContactLine">
       <div class="contactListItem" data-bind="text: ContactName, click: $root.CurrentDepartmentContacts.SelectContact, css: { contactListItemSelected: IsSelected() == true }"></div>
   </script>
   <script type="text/html" id="ContactDetails">
       <div class="contactDetails">
            <div>
                <h2>
                    <span data-bind="text: ContactName" style="color: #054b73"></span>
                </h2>
                <label>Office Phone: </label>
                <span data-bind="text: OfficePhone"></span>&nbsp;
                    <label>ext:</label>
                <span data-bind="text: OfficePhoneExt"></span>
                <br />
                <label>Fax: </label>
                <span data-bind="text: Fax"></span>
                <br />
                <label>Email: </label>
                <span data-bind="text: Email"></span>
            </div>
        </div>
   </script>


    <script type="text/javascript">
        var customerId = $("[id$=hdnCustomerId]").val();
        var orgModel = new CustomerOrgVM(customerId, "orgList", "orgChart2", 'divAddEditDepartment');

        function LoadCustomerOrgChart() {
            orgModel.LoadDepartments();

            ko.bindingHandlers.kendoTabStrip.animation = false;

            ko.applyBindings(orgModel);

            $w.Util.WaitAll(function () {
                // Build the Hierarchy after all departments and contacts have been loaded
                orgModel.BuildHierarchy();
                orgModel.IsLoaded(true);

                // Load Contacts Async after hierarchy is displayed
                orgModel.LoadContacts();
            });
        }

    </script>

Javascript

4

1 回答 1

1

首先,您的小提琴没有呈现嵌套模板,因为您忘记了内部模板名称周围的引号。你的代码:

template: { name : ContactLine, foreach: Contacts }

应该有这样的引号中的名称:

template: { name : "ContactLine", foreach: Contacts }

修复后,根据模板中发生的情况,1500 个项目可能是相当大的渲染量,尽管我曾参与过一些项目,我们在表格中推送这么多数据而没有太多麻烦。我们的减速实际上是从原始 JSON 映射到视图模型;渲染速度可以接受。

话虽如此,添加分页并不难,即使您想将所有数据保留在客户端以进行快速排序。如果您的瓶颈实际上是渲染而不是映射,那么分页可能会有所帮助。

另一种方法是构建一个自定义活页夹,以 25 或 100 个块呈现您的列表。然后您的应用程序可以响应用户,以便他们知道它正在工作,同时默默地继续在后台呈现。

我希望这有帮助!

于 2013-06-19T16:07:51.087 回答