1

我有 2 个 plunkr 准备好展示我的困惑。我正在寻求一个明确的解释,解释为什么第一个 plunkr 失败了,而第二个却有效。

在第一个 plunkr 中,我模拟调用外部库来执行某种网络身份验证。问题是,当原始控制器级别方法的链中有 2 个 Promise 时,传递给第一个 Promise 以在 resolve 时执行的函数永远不会触发,并且尽管解决了每个 Promise,但链中的任何其他 Promise 也不会触发。

http://plnkr.co/edit/6uKnVvEI3bJvfmaUoWN0

但是,当我将调用更改为使用 $timeout 时,无论它是用于模拟延迟,还是只是包装从实际外部操作(如调用 REST API)返回的 deferred.resolve,一切正常正如预期的那样。在第二个 plunkr 中,一旦将两个 deferred.resolve 调用都修改为包装在 $timeout 调用中,您就可以看到登录功能正常工作。

此外,我还包括了一个其他人建议的测试用例,作为在返回之前解决承诺会失败的问题。显然情况并非如此,因为第二个 plunkr 在这样做时工作得很好。请注意,此替代方法不使用 $timeout 但仍然可以正常工作。这向我表明,当两个服务(testApi、authService)都返回承诺对象导致必须向上解析的嵌套承诺链时,这两个服务(testApi、authService)之间的关系有些特殊。

http://plnkr.co/edit/xp8NeZKWDep6cPys5gJu?p=preview

有没有人能向我解释为什么这些承诺在一个实例中失败,但在它们没有嵌套或者嵌套在 $timeout 中时在另一个实例中起作用?

我的预感与摘要周期有关,但在我的一生中,我无法理解为什么摘要周期会影响基本上独立于控制器运行的服务。它们不是 $scope 上需要在控制器加载之前解析的属性,而是包装返回承诺的服务调用的函数。

4

1 回答 1

3

你的预感是对的。当你使用setTimeout时,它会触发一个 Angular 不知道的事件;如果您改用,情况并非如此$timeout。因此,要使您的第一个 Plunker 脚本正常工作,您需要通过调用手动启动摘要循环$rootScope.$apply()

angular.module('testApi', []).factory('testApi', function($q, $rootScope) {
...    
    setTimeout(function() { 
        $rootScope.$apply(function() { 
            deferred.resolve({user: { id: '1', name: 'bozo'}}); 
        });
    }, 1000);

Plunker在这里

如果您坚持使用 ,则无需执行上述任何操作$timeout,我建议您这样做。

这个SO question有更多关于为什么只在进入 $digest 循环时才调用承诺回调的信息。

于 2013-09-12T04:45:10.953 回答