当服务中存在嵌套的承诺关系时,AngularJS的行为很奇怪

AngularJS behaving strangely when there's a nested relationship of promises in services

本文关键字:AngularJS 关系 服务 存在 嵌套 承诺      更新时间:2023-09-26

我有 2 个 plunkr 准备好来演示我对什么感到困惑。我正在寻求一个明确的解释,确切地解释为什么第一个 plunkr 失败了,但第二个有效。

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

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

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

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

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

有谁能向我解释为什么这些承诺在一种情况下失败,但在另一种情况下,当它们没有嵌套或嵌套包装在$timeout中时起作用?

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

你的预感是对的。当你使用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);

在这里普朗克。

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

这个 SO 问题提供了更多关于为什么承诺回调仅在进入$digest周期时才调用的信息。