Ang-repeat的AngularJS性能问题

时间:2016-09-26 20:39:38

标签: javascript angularjs angularjs-ng-repeat

我在背景上有一个带有ruby-on-rails的Angularjs应用程序。当我发出一个http获取请求时,我恢复它的速度很快,我也没有遇到任何问题。问题出现在我已经获得了我想要的数据并且ng-repeat需要很长时间才能呈现(或者它可能不是ng-repeat,我真的不知道)。

下面的一些代码和图片:

我的桌子上有ng-repeat(我有更多的td' s,但即使只有id很慢):

<md-table-container>
    <div ng-if="showSpinner" layout="row" layout-align="center start">
        <p></p>
        <md-progress-circular ng-if="showSpinner" md-diameter="70"></md-progress-circular>
    </div>

   <table md-table>
       <thead md-head>
          <tr md-row>
             <th md-column>Situação</th>
             <th md-column>Inclusão</th>
             <th md-column>Tipo de CTe</th>
             <th md-column>Número/Série</th>
             <th md-column class="min-width200">Emissor</th>
             <th md-column class="text-align-right">Valor</th>
             <th md-column>Emissão</th>
             <th md-column>
                 <md-icon md-font-set="md">done_all</md-icon>
                 <md-tooltip md-direction="top">Recebimento</md-tooltip>
             </th>
             <th md-column class="max-width5 text-align-center">
                <md-icon md-font-set="md">computer</md-icon>
                <md-tooltip md-direction="top">SEFAZ</md-tooltip>
             </th>
          </tr>
       </thead>
       <tbody>
          <tr ng-mouseleave="dataover = 0" ng-mouseover="dataover = document.id" ng-class="{'selected-row': idSelectedDocument === document.id, 'not-selected-row': idSelectedDocument != document.id, 'document_row_active': dataover === document.id, 'document_row': dataover != document.id}" md-row ng-repeat="document in documents track by document.id">
            <td>{{document.id}}</td>
            <!--Even with only the id it is slow-->

         </tr>
      </tbody>
   </table>
 </md-table-container>

 <md-table-pagination md-limit="itemsPerPage" md-page="currentPage" md-total="{{totalItems}}" md-label="{page: 'Página:', rowsPerPage: 'Filas por página:', of: 'de'}" md-on-paginate="selectPage(currentPage)" md-page-select></md-table-pagination>

我的Http请求:

$scope.promise = $http.get("/documents.json",
          { "params": {"company_id": company_id} }
    ).success(
        function(data,status,headers,config) {
          $scope.documents = data.data;
          $scope.totalItems = data.paging;
          console.log("HERE");
    }).error(
        function(data,status,headers,config) {
          toastr.error("Error.");
  });

如上所述在JS中我有一个console.log(),即使在执行console.log之后,ng-repeat还没有准备好再花2,3秒。它甚至有时会冻结应用程序。

我安装了Angularjs Batarang以进行更多调试,下面是我的截图,我不认为它影响太大(从我的表angular md-data-table的组件中调用getColumn):

angularjs-batarang print

编辑1:在ng-repeat中使我的tds变得缓慢,试图逐个移除以查看它是哪一个但我认为它是所有这些的组合,你们可以帮我试试吗减少花时间?

<td md-cell>
      <div ng-mouseover="show_error_states($event, document)">
        <span ng-class="{'label-green': isApproved(document.current_state_id),
                          'label-red': isPending(document.current_state_id),
                          'label-yellow': isIncluded(document.current_state_id),
                          'label-orange': isDownloaded(document.current_state_id),
                          'label-dark-green': isLaunched(document.current_state_id),
                          'label-gray': isCancelled(document.current_state_id)}">{{document.current_state_title}}{{document.launched_by_erp ? '**' : ''}}</span>
        <md-tooltip md-direction="top">
          <span>{{document.current_state_view.description}}{{document.launched_by_erp ? ' **Lançado pelo ERP' : ''}}</span>
        </md-tooltip>
      </div>
    </td>

    <td md-cell ng-bind="document.received_date | date:'dd/MM/yyyy HH:mm'"></td>
    <td md-cell>{{document.dfe_number == null ? '----' : document.dfe_number + '/' + document.dfe_serie}}</td>
    <td md-cell>
      {{ document.emitter | limitTo: 35 }}{{document.emitter.length > 35 ? '...' : ''}}
      <md-tooltip md-direction="top">{{document.emitter + ' - ' + document.emitter_cnpj}}</md-tooltip>
    </td>
    <td md-cell class="text-align-right" ng-bind="document.dfe_value | currency: 'R$'"></td>
    <td md-cell ng-bind="document.dfe_dhemi | date: 'dd/MM/yyyy HH:mm'"></td>

    <td md-cell>
      <md-icon md-font-set="md">{{document.reception_state == "2" ? 'done' : 'clear'}}</md-icon>
      <md-tooltip md-direction="top">{{document.reception_state == "2" ? 'Recebido' : 'Pendente Recebimento'}}</md-tooltip>
    </td>

    <td md-cell class="text-align-center" ng-mouseover="find_dfe_situation(document)">
      <md-icon md-font-set="md">{{hasSuccessSefaz(document.dfe_situation) ? 'done' : ''}}{{hasErrorSefaz(document.dfe_situation) ? 'clear' : ''}}</md-icon>
      <md-tooltip ng-if="document.dfe_situation != null" md-direction="top">
        <div>
          <ul class="without-padding without-bullets">
            <li>
              <span>{{document.dfe_situation_description}}</span>
            </li>
            <li>
              <span ng-if="document.dfe_situation_date != null">{{' - ' + document.dfe_situation_date | date: 'dd/MM/yyyy HH:mm'}}</span>
            </li>
          </ul>
        </div>
      </md-tooltip>
    </td>


    <td md-cell class="text-align-center" ng-mouseover="find_manifestation(document)">
      <md-icon md-font-set="md">{{document.manifestation_state ? 'done' : 'clear'}}</md-icon>
      <md-tooltip ng-if="document.manifestation_state == true" md-direction="top">
        <div>
          <ul class="without-padding without-bullets">
            <li>
              <span>Descrição da Manifestação:</span>
              <span>{{document.manifestation_description}}{{document.manifestation_description == null ? 'Não Possui.' : ''}}</span>
            </li>
            <li>
              <span>Data da Manifestação:</span>
              <span>{{document.manifestation_date | date: 'dd/MM/yyyy HH:mm'}}{{document.manifestation_date == null ? 'Não Possui.' : ''}}</span>
            </li>
          </ul>
        </div>
      </md-tooltip>
    </td>

    <td md-cell>
      <md-button ng-click="openDanfe(document); setSelectedDocument(document.id)" ng-disabled="document.current_state_id == 17" class="md-raised min-width5">
        <md-icon md-font-set="md">find_in_page</md-icon>
        <md-tooltip md-direction="top">Danfe</md-tooltip>
      </md-button>

      <md-menu md-position-mode="target-right target" md-offset="45 35">
        <md-button class="min-width5" aria-label="Abrir menu" ng-click="$mdOpenMenu($event); open_documents_menu(document)">
          <div md-menu-origin>
            <md-icon class="color-blue" md-menu-origin md-font-set="md">settings</md-icon>
          </div>
        </md-button>
        <md-menu-content>
          <md-menu-item>
            <md-button ng-click="open_nfe_process(document); setSelectedDocument(document.id)" ng-disabled="document.current_state_id == 17 || document.current_state_id == 5 || document.launched_by_erp">
              Processo
            </md-button>
          </md-menu-item>
          <md-menu-item>
            <md-button ng-click="launch_now(document, $event); setSelectedDocument(document.id)" ng-disabled="document.current_state_id != 20">
              Lançar no ERP
            </md-button>
          </md-menu-item>
          <md-menu-item permission only="'admin'">
            <md-button ng-click="delete_now_erp(document, $event); setSelectedDocument(document.id)" ng-disabled="document.current_state_id != 21 || document.launched_by_erp">
              Excluir no ERP
            </md-button>
          </md-menu-item>
          <md-menu-item>
            <md-button ng-click="files(document, $event); setSelectedDocument(document.id)">
              Gerenciar Anexos
            </md-button>
          </md-menu-item>
          <md-menu-item>
            <md-button ng-click="manifest(document, $event); setSelectedDocument(document.id)">
              Manifestar
            </md-button>
          </md-menu-item>
          <md-menu-item>
            <md-button ng-click="events(document, $event);  setSelectedDocument(document.id)">
              Ocorrências
            </md-button>
          </md-menu-item>
          <md-menu-item>
            <md-button ng-click="nfe_events(document, $event); setSelectedDocument(document.id)">
              Eventos do Documento
            </md-button>
          </md-menu-item>
        </md-menu-content>
      </md-menu>
    </td>

2 个答案:

答案 0 :(得分:1)

您可以对ng-repeats进行的最佳性能改进之一是填充您在块中重复的数组,以便分批呈现表行而不是一次性呈现。这允许浏览器在渲染表时执行其他操作,而不是将所有精力都集中在渲染表上。

在实践中,你可以在你的成功函数中做这样的事情(使用$ q链接promises和Lodash使分块变得更容易)并且当文档被添加到$ scope上的文档数组时它们将被渲染到DOM:

$scope.promise = $http.get("/documents.json",
      { "params": {"company_id": company_id} }
).success(
    function(data,status,headers,config) {
      let collection = data.data;
      // split the collection into smaller chunks; pick the size of each batch here
      let chunkedCollection = _.chunk(collection, size);
      let nextToRender;

      let promise = $q.resolve();

      function renderChunk(chunk) {
          // returning a $timeout ensures that each chunk is queued to be rendered seperately
          Array.prototype.push.apply($scope.documents, chunk);
          return $timeout(function(){}, 0);
      }

      _.forEach(chunkedCollection, function(chunk, index) {
          // we need to bind each chunk to the render function because of the $timeout
          nextToRender = renderChunk.bind(null, chunk);
          // $timeout returns a promise, so it's necessary to chain them like this
          promise = promise.then(nextToRender);
      });

      $scope.totalItems = data.paging;
      console.log("HERE");
}).error(
    function(data,status,headers,config) {
      toastr.error("Error.");
});

答案 1 :(得分:0)

您可以在此处进行常见的性能增强,实际上是将代码移至服务中,然后将您的服务注入md-row以访问您的数据。这里性能如此之慢的一个重要原因是因为md-row指令中的作用域绑定。所以..

  1. 在服务中获取数据,然后将值分配给服务。

  2. 创建一个没有范围绑定的md-table-content类型指令,该指令将服务注入其中,然后将服务变量的值分配给范围。

  3. 将ng-repeat移动到md-table-content指令的模板中,并在md-table-content上创建$ scope变量或函数,以便更快地评估该巨型ng-class逻辑。或者更好的是尝试将其中一些类折叠成if = document.id - &gt;的简单逻辑。申请活跃,否则申请非活跃或类似的行