$scope.$apply()调用是否适用于此场景?

Is the $scope.$apply() call warranted for this scenario?

本文关键字:适用于 调用 scope apply 是否      更新时间:2023-09-26

对于AngularJS(坦白说也是JavaScript)来说还是个新东西,但是从我收集到的信息来看,只有当变化发生在angular的雷达之外时,才需要显式调用$scope.$apply()。下面的代码(从这个柱塞中粘贴进来)让我认为这不会是一个需要调用的情况,但这是我能让它工作的唯一方法。我应该采取什么不同的方法吗?

index . html:

<html ng-app="repro">
  <head> 
    ...
  </head>
  <body class="container" ng-controller="pageController">
    <table class="table table-hover table-bordered">
        <tr class="table-header-row">
          <td class="table-header">Name</td>
        </tr>
        <tr class="site-list-row" ng-repeat="link in siteList">
          <td>{{link.name}}
            <button class="btn btn-danger btn-xs action-button" ng-click="delete($index)">
              <span class="glyphicon glyphicon-remove"></span>
            </button>
          </td>
        </tr>
    </table>
  </body>
</html>

script.js:

var repro = angular.module('repro', []);
var DataStore = repro.service('DataStore', function() {
  var siteList = [];
  this.getSiteList = function(callback) {
    siteList = [ 
      { name: 'One'}, 
      { name: 'Two'}, 
      { name: 'Three'}];
    // Simulate the async delay
    setTimeout(function() { callback(siteList); }, 2000);
  }
  this.deleteSite = function(index) {
    if (siteList.length > index) {
      siteList.splice(index, 1);
    }
  };
});
repro.controller('pageController', ['$scope', 'DataStore', function($scope, DataStore) {
  DataStore.getSiteList(function(list) {
    $scope.siteList = list; // This doesn't work
    //$scope.$apply(function() { $scope.siteList = list; }); // This works
  });
  $scope.delete = function(index) {
    DataStore.deleteSite(index);
  };
}]);
setTimeout(function() { callback(siteList); }, 2000);

这一行将带你离开angular的digest循环。你可以简单地用Angular的$timeout包装器替换setTimeout(你可以把它注入到你的DataStore服务中),而不需要$scope.$apply

setTimeoutasync事件,被认为是angular上下文之外的事件,因此它不运行摘要循环。当你做这样的事情时,你需要手动运行它,但更喜欢使用$timeout

相反,angular提供了一个$timeout服务,它的工作原理与setTimeout相同,但在执行回调函数后,它会调用$scope.$apply()

$timeout(function() { callback(siteList); }, 2000);

$timeout的特殊之处在于它运行的是摘要循环更安全的方式。它给你一个保证,它不会与任何冲突当前正在运行摘要循环。在幕后,当你调用$timeout内部的函数时,它会通过检查$scope.root.$$phase来检查是否有任何摘要周期在运行,如果它在digest阶段,它会将该摘要周期放入队列并在该摘要周期完成后运行它。