angularjs deferred承诺不推迟

时间:2015-01-09 20:08:26

标签: javascript angularjs promise deferred angular-promise

努力让promise在promisejs服务提供商中正常工作 我已经阅读了docs以及众多示例(hereherehere),我认为我的语法还可以 (虽然显然有些事情是错误的)

app模块和控制器看起来像

var myApp = angular.module('myApp', []);

myApp.controller('Controller_1', ['$scope', 'Service_1', function($scope, Service_1) {

    var myName = "Ben";

    Service_1.slowService(myName)
        .then(Service_1.fastService(name));

    $scope.myName = myName;
}]);

服务(具有慢速功能)如下所示:

myApp.service('Service_1', function($q) {
    this.slowService = function (name) {
        var deferred = $q.defer();
        console.log('Start of slowService:', name, Date.now());

        setTimeout(function() {
            console.log('setTimeout name:', name, Date.now());

            if(name){
                name = 'Hello, ' + name + " is learning Angularjs";
                alert(name); 
                    console.log('name:', name);
                deferred.resolve(name);
            } else {
                deferred.reject('No name supplied !');
            }
        }, 3000);

        return deferred.promise;
    };

    this.fastService = function(name){ 
        console.log('Start of fastFunction:', name, Date.now());
        alert('Hello ' + name + ' - you are quick!'); 
    }; 
});

控制台输出如下所示:

Start of slowService: Ben 1420832940118
Start of fastFunction: result 1420832940122
setTimeout name: Ben 1420832948422
name: Hello, Ben is learning Angularjs

fastServiceslowService完成之前开始,尽管在Service_1中使用了延迟对象/承诺并且在控制器中使用了.then ...

任何人都可以指出代码有什么问题吗?

jsfiddle是here

编辑:将快速功能放入服务中,这样就不会出现提升等问题 - 仍然是相同的结果 - js fiddle updated

4 个答案:

答案 0 :(得分:5)

  

fastService在slowService完成之前启动

这是因为你在slowService异步回调运行之前执行函数fastService。而你想要提供函数的引用。即.then(Service_1.fastService(name));应为.then(Service_1.fastService);.then(function(name){ Service_1.fastService(name); });,否则fastservice将在slowService的异步部分运行之前立即运行。

使用$timeout的优点是它已经返回了一个promise,因此您不需要创建一个延迟对象并导致deferred anti-pattern

myApp.service('Service_1', function($q, $timeout) { //<-- Inject timeout
    this.slowService = function (name) {
        console.log('Start of slowService:', name, Date.now());

        return $timeout(function() {
            console.log('setTimeout name:', name, Date.now());

            if(name){
                name = 'Hello, ' + name + " is learning Angularjs";
                return name; //return data
           }
           //Reject the promise
           return $q.reject('No name supplied !');

        }, 3000);


    };
   //...
});

当消费只是通过链接:

  Service_1.slowService(myName)
     .then(Service_1.fastService);

因此,即使您在原始方法中使用$http,也不要超时,只需从http返回promise,而不是创建延迟对象。另外,在使用语法.then(Service_1.fastService);时请记住,如果您在快速服务中引用this上下文,则它不会是服务实例。

答案 1 :(得分:2)

将函数传递给then()部分的方式不正确。 像这样传递:

Service_1.slowService(myName)
         .then(function(){fastFunction(name)});

答案 2 :(得分:1)

由于您的slowService使用name值解析,因此将作为您传递到then的函数的参数提供。你可以这样做:

Service_1.slowService(myName)
.then(function(name){ Service_1.fastFunction(name); });

但即使这是多余的,因为您只是将name移交给另一个带有name参数的函数。

这就是你所需要的:

Service_1.slowService(myName)
.then(Service_1.fastFunction);

请注意,第二行中没有(name)。我们希望将函数传递给then。你正在做的是立即调用函数并将undefined传递给then

答案 3 :(得分:1)

YAAK是对的。你也可以这样写:

Service_1.slowService(myName) .then(fastService);

只是澄清一下我非常肯定会发生什么:

then函数正在注册解析或拒绝承诺的回调。您不需要传递函数参数,因为当您resolve使用您尝试传递给回调函数的任何数据时,这已经完成了。当你在那里有fastService(name)时,它只是在它触及那行代码时执行该函数而不等待解析的承诺,因为它是一个函数调用,而不是一个函数对象。

有趣的是,fastService将'result'作为名称返回,而不是说该名称未定义。我不知道从哪里得到该变量的值。