AngularJS $ q.resolve(),ES6 Promise.resolve()(以及其他动物)

时间:2015-12-29 17:24:12

标签: javascript angularjs promise angular-promise

免责声明:这里有两个问题,但我觉得它们密切相关。

我正在尝试将promise对象传递给指令,并且我希望在promise解析后立即在指令中运行一些初始化代码。

在控制器中我有:

$scope.item = $http.get(...)
    .success(function (result) {
        $scope.item = result.item;
});

$scope.item传递给指令(通过名为item的隔离范围中的属性)。 指令链接函数最终执行如下操作:

Promise.resolve(scope.item)
    .then(function () {
        initialize();
});

这在Firefox中工作正常,但是当我在IE上运行时,我收到错误,因为没有定义Promise。这个问题让我意识到我需要使用AngularJS $ q服务以提供浏览器之间的一致性,当我查看文档时,我发现了另一个问题,一开始看起来很小但实际上让我头疼:{ {1}}函数已弃用,我应该使用success()代替。我想,很轻松,但是一旦我在控制器中更改then(successCallback)调用,代码就会停止在Firefox中运行!我无法弄清楚为什么。所以这是第一个问题。

第二个问题是(即使我将成功调用留在控制器中)如果我修改指令链接函数中的代码以使用$ q与我认为相同的东西:

success

这根本不起作用。有什么建议吗?

4 个答案:

答案 0 :(得分:4)

您需要使用Angular的$q,不仅因为它适用于各种浏览器,还因为它是deeply linked to Angular's digest cycles。其他承诺库can accomplish this feat但本机承诺不能轻易做到。

$q.when做什么({q}版本的Promise.resolve)将值或承诺转换为$q承诺。您不需要这样做,因为您已经使用了Angular自己的$http API,它已经返回了承诺。

我热烈建议您将您的网络电话放在服务中,不要直接影响范围 - 然后调用这些服务来更新范围。

模式基本上是:

$http.get(...) // no assign
    .success(function (result) { // old API, deprecated
      $scope.item = result.item; // this is fine
});

或者使用has the benefits of promises over callbacks更好的then承诺API,以及链接和错误处理:

$http.get(...).then(function (result) {
  $scope.item = result.data;
});

答案 1 :(得分:0)

您对弃用的.success方法是正确的。 .then方法返回的数据与.success方法不同。

$scope.httpPromise = $http.get(...)
    .then(function (result) {
        $scope.item = result.data.item;
        return result.data;
});

您需要将数据>返回

$scope.httpPromise.then ( function (data) {
     //Do something with data
     initialize();
});

有关弃用.success方法的详细信息,请参阅AngularJS $http Service API Reference -- deprecation notice

答案 2 :(得分:-1)

由于scope.item是一个承诺,你所要做的就是:

scope.item.resolve.then(function() { initialize(); });

确保在你的指令中注入$ q。

答案 3 :(得分:-1)

改进答案

正如@ benjamin-gruenbaum所说,我在答案中使用了反模式。因此,解决方案基本上是将承诺传递给您的指令并在那里使用(如Benjamins的答案中所述)。

工作jsFiddle:https://jsfiddle.net/eovp82qw/1/

旧答案,使用反模式

很抱歉,如果我给你的解决方案可能与你的代码差别太大。但也许你可以将它用于你的解决方案。

我的方法是创建第二个承诺,我将其移交给您的指令。这是解决指令等待状态的一种更简洁的方法,不会为两个不同的任务重用相同的范围变量。

<强> HTML

<body ng-app="myApp">
    <div ng-controller="MyCtrl">
        <my-directive promise="promiseFromController"></my-directive>
    </div>
</body>

<强> JS

function MyCtrl($scope, $q, $http) {
    function init() {
        var deferredCall = $q.defer();

        // simulated ajax call to your server
        // the callback will be executed async
        $http.get('/echo/json/').then(function(data) {
            console.log('received', data);
            deferredCall.resolve(data); //<-- this will resolve the promise you'll handover to your directive
        });

        // we're return our promise immediately
        $scope.promiseFromController = deferredCall.promise;
    }
    init();
 }

angular.module('myApp',[])
.controller('MyCtrl', MyCtrl)
.directive('myDirective', function() {
    return {
        scope: {
            promise: '='
        },
        controller: function($scope) {
            console.log($scope);
            $scope.promise.then(function(data) {
                console.log('received data in directive', data);
            });
         }
    }
})

工作jsFiddle:https://jsfiddle.net/1ua4r6m0/ (没有输出,请检查浏览器控制台;))