我有 2 个 plunkr 准备好展示我的困惑。我正在寻求一个明确的解释,以准确说明为什么第一个 plunkr 失败,而第二个 plunkr 有效。
在第一个 plunkr 中,我模拟调用外部库来执行某种网络身份验证。问题是,当来自原始 Controller 级别方法的链中有 2 个 promise 时,传递给第一个 promise 以在 resolve 时执行的函数永远不会触发,并且尽管解决了每个 promise,也不会触发链中更远的任何其他 promise。
http://plnkr.co/edit/6uKnVvEI3bJvfmaUoWN0
但是,当我将调用更改为使用 $timeout 时,无论它是用于模拟延迟,还是只是包装从实际外部操作返回的 deferred.resolve(例如调用 REST API) ,一切都按预期工作。在第二个 plunkr 中,您可以看到登录功能在两个 deferred.resolve 调用都被修改为包含在 $timeout 调用中后工作得很好。
此外,我还包含了一个测试用例,其他人建议将其作为在返回 promise 之前解决 promise 失败的问题。这显然不是这种情况,因为第二个 plunkr 在这样做时工作得很好。请注意,此替代方法不使用 $timeout 但仍然可以正常工作。这向我表明,当两个服务(testApi、authService)都返回 promise 对象时,这两个服务(testApi、authService)之间的关系有一些特殊之处,导致必须向上解析的嵌套 promise 链。
http://plnkr.co/edit/xp8NeZKWDep6cPys5gJu?p=preview
有谁能向我解释为什么这些 promise 在一个实例中失败,但在另一个实例中没有嵌套,或者嵌套在 $timeout 中时有效?
我的直觉与摘要周期有关,但我无法理解为什么摘要周期会影响本质上独立于 Controller 运行的服务。它们不是 $scope 上需要在 Controller 加载之前解析的属性,而是包装返回 promise 的服务调用的函数。
最佳答案
你的预感是对的。当你使用 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);
笨蛋 here .
如果您坚持使用 $timeout
,则无需执行上述任何操作,我建议您这样做。
这SO question有更多关于为什么只在进入 $digest 周期时才调用 promises 回调的信息。
关于javascript - 当服务中存在嵌套的 promise 关系时,AngularJS 表现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18755383/