【问题标题】:Angular UI Router promise resolution and transitionAngular UI Router 承诺解决和转换
【发布时间】:2014-04-10 22:23:30
【问题描述】:

我正在使用 ui-router 0.2.0(我知道它是旧版本,但由于各种原因我们被锁定在 Angular 1.0.8 上)并尝试使用 resolve: {} 来确保控制器正在处理具体数据而不是最终数据(承诺)。

我目前有以下:

resolve: {
    items: ['listSvc', function (listSvc) {
        console.log('resovling items');
        var items = listSvc.getItems();
        items.then(function () {
            console.log('horray!');
        });
        return items;
    }]
}

现在项目包含大约八个项目,只有一个标题,我的视图只是执行 ng-repeat 并显示每个标题。

控制器:

App.controller('MyCtrl', ['$scope', 'items', function ($scope, items) {
    console.log('MyCtrl');
    $scope.items = items;
}]);

观点:

<div>
    <h1>Items</h1>
     <div data-ng-repeat="item in items">
        {{ item.Title }}
    </div>
</div>

有时我看到“万岁!”之间的间隔大约为 2 秒。以及由此产生的视图。其他时候我看到“万岁!”但永远不要过渡到预期的视图。如何解决/解决此问题?

如果重要的话,我的 listSvc 也使用 Q 而不是 $q。

编辑:为了清晰起见,将问题移至底部

编辑:

虽然所选答案适用于我的所有 jsbin 测试,并且根据我找到的所有文档都是正确的。这是解决我实际问题的方法,我知道它令人讨厌和可怕,但这是我唯一可以为我们的应用程序工作的东西。在下面的示例中,我的 listSvc 使用的是Q

    resolve: {
        items: ['listSvc', 'currentUser', '$q', '$rootScope', function (listSvc, currentUser, $q, $rootScope) {
            console.log('my => items');
            var deferred = $q.defer();
            listSvc.setUser(currentUser);
            listSvc.getMyItems().then(function (myItems) {
                deferred.resolve(myItems);
                return myItems;
            }).fin(function () {
                $rootScope.$apply();
            });
            return deferred.promise;
        }]
    }

【问题讨论】:

  • 您的问题/疑问是什么?
  • 有时我看到“万岁!”之间的间隔大约为 2 秒。以及由此产生的视图。其他时候我看到“万岁!”但永远不会转换到预期的视图。

标签: angularjs promise angular-ui-router q


【解决方案1】:

如果重要的话,我的 listSvc 也使用 Q 而不是 $q。

是的,是的。这是你的问题。

Q 是一个比 $q 更完整的 Promise 实现,它有更多的功能。但是$q 集成到 AngularJS 的摘要循环中。

  • 非正式地 - 它通知演示文稿某些内容已更改并且需要刷新。
  • 正式 - Q 使用 asap.js 模块解决承诺以实现快速排队(最近),并且 $q 解决 evalAsync 队列上的承诺。不过,非正式的部分在这里更为重要。

我的建议是,不要在.finally 中统一使用诸如作用域之类的技巧-使用$q.when(prom),这是一种实用方法,它采用thenable(通用承诺)并将其转换为受信任的$q 承诺。如果你没有任何在 $q 中运行的东西,你仍然需要在你的 Promise 链的末尾调用 $rootScope.$apply()。

如果这不起作用,您可以简单地添加

.finally(function(){ $scope.apply(); }) 

到你的承诺链的末端。

大多数优秀的 Promise 库都实现了 A+ 规范,该规范允许将一种 Promise 干净且简单地同化到另一种 Promise 中。由于 Q 和 $q 都是 Promises/A+ 投诉 - 这意味着您可以非常轻松地在 Q 和 $q 之间进行互操作(因为它们具有相似的 .then 语义):

when(value) - 将可能是值或(第 3 方)then-able 承诺的对象包装成 $q 承诺。当您处理的对象可能是也可能不是 Promise 时,或者当 Promise 来自不可信的来源时,这很有用。

在你的情况下 - 类似:

var items = $q.when(listSvc.getItems()); // don't forget to inject $q

或者在链中的任何其他点将其包装在when 中。

【讨论】:

  • 当直接使用$q 时,我的promise 似乎无法正确解析,当使用$rootScope.$apply() 和Q 或$q.when() 时,除非我在父视图中单击,否则我的用户界面不会更新文本框。这似乎特定于我的应用程序,因为如果我制作类似的 jsbin 一切正常。这种行为是否表明我应该查看特定的内容?
  • @RyanHirsch 和 $scope.apply() 在 Q 承诺的 .finally 中不起作用?
  • 不在我的实际应用程序中没有:(我已经用我的场景中的工作更新了我的原始问题,但是,根据我在应用程序之外测试的所有内容,您的答案是正确的。
  • 所以你明确地将 Q 承诺转换为 $q 承诺和 $apply ?我想知道为什么.fin 中的$apply 还不够。有趣的。如果您可以创建一个示例(或最终错误地创建一个示例),请告诉我,我会看看 :)
猜你喜欢
  • 2014-03-19
  • 1970-01-01
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2017-03-18
  • 1970-01-01
  • 2015-12-06
相关资源
最近更新 更多