什么时候使用$ scope是安全的.$ apply()?

Zee*_*Zee 14 javascript ajax angularjs

我想这个标题非常清楚我要问的是什么.我创造了这个小提琴:http://jsfiddle.net/Sourabh_/HB7LU/13142/

在小提琴中,我试图复制一个async场景.这只是一个例子,但在AJAX调用中如果我不使用$scope.$apply()该列表则不会更新.我想知道$scope.$apply()每次进行AJAX调用更新列表时是否安全使用,还是有其他一些我可以使用的机制?

我编写的代码用于复制场景(与小提琴相同):

HTML

<div ng-controller="MyCtrl">
  <li ng-repeat="item in items">
    {{item.name}}
  </li>
  <button ng-click="change()">Change</button>
</div>
Run Code Online (Sandbox Code Playgroud)

JS

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
  $scope.items = [{name : "abc"},{name : "xyz"},{name : "cde"}];

  $scope.change = function(){
    test(function(testItem){
      $scope.items = testItem;
      //$scope.$apply();
    })
  }
  function test(callback){
    var testItem = [
                    {name : "mno"},
                    {name : "pqr"},
                    {name :   "ste"}
                   ];
    setTimeout(function(){callback(testItem)},2000);
  }
}
Run Code Online (Sandbox Code Playgroud)

tho*_*aux 6

编辑目前尚不清楚OP正在试图模拟后端调用.即便如此,使用该$timeout服务是避免$scope.$apply手动调用的一种很好的方法,并且是一种比使用Promise更普遍适用的解决方案(如果你没有调用$http它,并不总是有意义强制你的更改用Promise包装它们的下一个循环).


更新您的代码以使用$ timeout服务,它应该工作而无需调用$apply.

$timeout是本机的包装器setTimeout,具有重要的区别:$timeout将至少延迟执行直到下一个$digest周期运行.

因此,毫不拖延地传递将仍然延迟执行直到下一个周期.2000年通过将延迟执行到2000ms后的下一个周期.

因此,这是一个简单的技巧,以确保您的更改被Angular选中,而无需$apply手动调用(在任何情况下都被视为不安全)

function MyCtrl($scope, $timeout) {
  $scope.items = [{name : "abc"},{name : "xyz"},{name : "cde"}];

  $scope.change = function(){
    test(function(testItem){
      $scope.items = testItem;
      //$scope.$apply();
    })
  }
  function test(callback){
    var testItem = [
                    {name : "mno"},
                    {name : "pqr"},
                    {name :   "ste"}
                   ];
    $timeout(function(){callback(testItem)},2000);
  }
}
Run Code Online (Sandbox Code Playgroud)


Iva*_*cev 6

每次使用非“角度方式”的东西时,都需要使用 $apply,就像 Anzeo 所说的 $timeout 一样。
例如,如果您使用 jQuery 的 http 而不是 Angular 的 $http,则必须添加 $scope.$apply。


Bas*_*ber 5

如果您想要移植API-Rest-Call,请使用promiseController在Rest-Call中设置范围的返回值.

$http.get('uri')
  .success(function(data) {
    $scope.items = data
});
Run Code Online (Sandbox Code Playgroud)

避免使用$apply().来自Angular GitHub Repo:

$scope.$apply() 应该尽可能接近async事件绑定.

不要在整个代码中随意撒上它.如果你这样做 (!$scope.$$phase) $scope.$apply()是因为你在调用堆栈中不够高.

对于你的问题:

  • 如果您发现自己处于需要$ apply()的情况,请重新考虑您的结构.
  • 出于安全原因:永远不要使用 $apply()