当服务中存在嵌套的Promise关系时,AngularJS的行为会很奇怪 [英] AngularJS behaving strangely when there's a nested relationship of promises in services

查看:42
本文介绍了当服务中存在嵌套的Promise关系时,AngularJS的行为会很奇怪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有2位朋克准备演示我的困惑.我正在寻找一个明确的解释,以确切地解释为什么第一个笨拙的人"失败了,而第二个却失败了.

I have 2 plunkr's ready to demonstrate what I'm confused about. I am seeking a clear explanation as to precisely why the first plunkr fails, yet the second works.

在第一个插件中,我模拟了对外部库的调用以进行某种网络身份验证.问题是,当原始控制器级别方法的链中有2个Promise时,传递给第一个Promise的函数将在解析时执行,但从不触发,即使解决了每个Promise,链中的其他Promise也不会进一步执行.

In this first plunkr, I simulate calling into an external library to do some kind of networked authentication. The problem is, when there are 2 promises in the chain from the original controller level method, the function passed to the first promise for execution upon resolve never fires and neither do any other promises further down the chain despite resolving each promise.

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

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

However, when I change the calls to use a $timeout, regardless of whether it is used to simulate a delay, or just to wrap a deferred.resolve that comes back from an actual external operation (like calling a REST API), everything works as expected. In this second plunkr, you can see the login functionality working just fine once both deferred.resolve calls have been modified to be wrapped in a $timeout call.

此外,我还提供了一个测试用例,该测试用例是其他人建议的问题,即在兑现承诺之前解决承诺将失败.显然不是这种情况,因为第二个插件确实可以正常工作.请注意,此替代方法不使用$ timeout,但仍然可以正常工作.这向我表明,当两个服务(testApi,authService)都返回promise对象,导致嵌套的promise链必须向上解析时,这两个服务之间的关系存在一些特殊之处.

Additionally, I included a test case that someone else suggested as the problem where resolving a promise before returning it would fail. This is clearly not the case as this second plunkr works just fine when doing precisely that. Note that this alternate method does not use a $timeout but still works just fine. This indicates to me that there is something special about the relationship between the two services (testApi, authService) when both return promise objects resulting in a chain of nested promises that have to resolve upwards.

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

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

Is anyone able to explain to me why these promises fail in one instance but work in another when they are either not nested, or if nested wrapped in a $timeout?

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

My hunch is something related to the digest cycle, but for the life of me I cannot understand why the digest cycle would affect services running essentially independent of a controller. They are not properties on the $scope that need to resolve before the controller loads, but functions wrapping service calls that return a promise.

推荐答案

您的直觉是正确的.当您使用 setTimeout 时,它将触发Angular一无所知的事件.如果您改用 $ timeout ,则不是这种情况.因此,要使第一个Plunker脚本起作用,您需要通过调用 $ rootScope.$ apply():

Your hunch is right. When you use setTimeout, it triggers an event Angular knows nothing about; that's not the case if you use $timeout instead. So, for your first Plunker script to work, you need to start a digest cycle manually by calling $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 ,则无需执行上述任何操作,我建议您这样做.

You won't need to do any of the above if you stick with $timeout, and I suggest that you do that.

SO问题具有有关为什么承诺的更多信息回调仅在进入$ digest周期时调用.

This SO question has more info on why promises callbacks are only called upon entering a $digest cycle.

这篇关于当服务中存在嵌套的Promise关系时,AngularJS的行为会很奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆