$http 何时触发脏检查循环启动?

3
我的假设是它在 .success 回调执行后发生,而不是在以下情况下:
  • .success 回调完成之前。
  • 请求发送后立即。

考虑以下代码:

notes.service.js

angular.module('notes').service('notes', ['$http', 
function($http) {
    var obj = {};

    this.getNotes = function() {
        $http.get('/notes').success(function(notesResponse) {
            obj.notes = notesResponse;
        });
        return obj;
    };
}]);

notes.controller.js

angular.module('notes').controller('NotesCtrl', ['notes', 
function(notes) {
    /* 
        $scope.$$watchers = [
            'notesCtrl.obj', cb
        ];
    */

    this.obj = notes.getNotes();    
}]);

list.html

<div class='page-header'>
    <h1>List of Notes</h1>
</div>

<ul>
    <li ng-repeat='note in notesCtrl.obj.notes track by note.id'>{{note | json}}</li>
</ul>

想象一下,GET请求在发送响应之前需要一个小时的时间。

  • 服务将返回{}
  • 在控制器中,this.obj将被设置为{}
  • 在视图中,notesCtrl.obj.notes将是undefined,因此ng-repeat不会发生。
  • 一小时后,当响应返回时…它会更新该对象。服务指向它,控制器指向它,视图也指向它。因此它们都被“更新”了(实际上是对象被更新了;指针没有改变,所以它们并没有真正被“更新”)。
  • 响应触发.success的回调函数,进行更新,一旦.success的回调函数完成,就会启动一个digest循环。
  • digest循环看到notesCtrl.obj已经改变,因此运行相应的回调函数,更新DOM。

这样正确吗?

另外,$http触发$digest还是$apply?如果它触发$digest,那么它如何知道在哪个$scope上调用它?例如,服务中的$http$scope无关(是吗?)。


遇到了类似的问题。在进行 $http 调用并更新原始对象后,与其绑定的视图得到了更新,但是最终原始对象的属性又变成了未定义。有人能提供一些建议吗? - Saurabh Tiwari
2个回答

2

几乎是正确的:成功回调实际上是在digest周期中调用的。如果您尝试以下操作,可以看到这一点

$http.get('test.json').success(function(result) {
  $scope.$apply();
});

假设 GET 请求到 test.json 成功,Angular 将会抛出一个错误,可以在控制台中看到:

 Error: [$rootScope:inprog] $digest already in progress

这可以在http://plnkr.co/edit/wj4z1hDRXtK2GJnrkKuV?p=preview中看到。此外,$http是否会触发$digest或$apply?$apply会触发全局digest来检查所有作用域,因为它确实不知道需要检查哪些作用域。请注意保留HTML标签。

所以只是确认一下 - 在 HTTP 响应需要一个小时才能返回的情况下,当它回来时会触发 $digest 以更新 DOM 吗? - Adam Zerner

0

我查看了 $http 的文档docs(Line:1083),找到以下代码行:

/**
* Callback registered to $httpBackend():
* - caches the response if desired
* - resolves the raw $http promise
* - calls $apply
*/

这段代码中说,回调函数注册到 $httpBackend(),然后按照以下顺序执行下列操作:如果需要缓存响应,则缓存响应(是否需要缓存取决于你在 $http 方法中是否提供 true)。之后解析 $http promise,即根据响应调用 success 或 error 方法(也可以使用 then())。最后调用 $apply 函数进行 digest cycle。

从文档中我们可以了解到,$http 服务与 $rootScope 绑定。

如果你认为在 success 函数中 $apply 在 $apply 后抛出错误,那么答案就在文档中,因为 $rootScope.$applyAsync 始终在运行并解析 httppromise,然后再运行 $rootScope.$apply()。(Line:1102-1106)

希望这能解决你的疑惑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接