2013-06-19 54 views
2

我有一个页面,在网格中按字母组合联系人。对于我更大的联系人(1000-1500),网格负载非常慢(分钟)。但是,浏览器几乎锁定,所以人们认为它崩溃了。嵌套模板foreach性能

根据铬探查器,我花了91%的时间在我最近的最大敌人.InnerHTML()。

从我可以告诉我,当填写联系人observables时,我不发出不必要的通知。

我试图提炼出页面到这个jsFiddle中的一个简单的窗体。

http://jsfiddle.net/DCLaR/105/(感谢瑞安Rahlf固定这)

它看起来像简单的版本罢了好了,所以必须有其他人在混合什么。

我打算继续并发布我的整页html,尽管它有点乱。

开始于实际网页代码中的小提琴,不退出运行,也许是太复杂,在那里馅:http://jsfiddle.net/DCLaR/108/

也许有人可以发现一些关闭或已知能够导致性能问题。

我看到了This这个问题是相似的,但没有得到它的解决方案。

的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的

回答

1

首先,你的小提琴不渲染嵌套的模板,因为你忘了周围的内模板名称您的报价。您的代码:

template: { name : ContactLine, foreach: Contacts } 

应该在这样的报价有名称:

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

随着那固定的,1500个项目可以根据模板是怎么回事渲染的一个相当大的量,虽然我我们正在开展一些项目,我们正在努力推动表格中的大量数据,而没有太多的麻烦。我们的减速实际上是从原始JSON映射到视图模型;渲染速度可以接受。

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

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

我希望这有助于!

+0

好的眼光在报价,我要更新问题中的小提琴。我喜欢自定义绑定的想法,但会留下一个问题,看看其他人是否有其他优点 –

+0

嗯,在玩这个例子中的数字后,看起来我有另一个隐藏在某个地方的问题。我可以在每封信中做100个项目,并且仍然可以像第二个一样加载。 –

+0

其中一些将取决于您的内部绑定对于每个元素模板的复杂程度。例如,如果您在1500个元素上执行大型ko.com或15个元素,则会降低您的速度。而且,正如我所提到的,长时间延迟可能不仅仅是渲染,它可能包括检索数据并解析或映射它。 –