【问题标题】:angularjs deferred promise not deferringangularjs延迟承诺不延迟
【发布时间】:2015-03-08 05:39:47
【问题描述】:

努力让承诺在 angularjs 服务提供商中正常工作 我已经阅读了docs 以及许多示例(hereherehere),我认为我的语法没问题 (虽然显然出了点问题)

应用模块和控制器看起来像

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

【问题讨论】:

标签: javascript angularjs promise deferred angular-promise


【解决方案1】:

fastService 在 slowService 完成之前启动

那是因为您在 slowService 异步回调运行之前执行了函数 fastService。相反,您希望提供函数的引用。即 .then(Service_1.fastService(name)); 应该是 .then(Service_1.fastService);.then(function(name){ Service_1.fastService(name); }); 否则 fastservice 将在 slowService 的异步部分运行之前立即运行。

使用$timeout 的好处是它已经返回了一个承诺,因此您不需要创建延迟对象并导致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 返回承诺,而不是创建延迟对象。还请记住,当您使用语法 .then(Service_1.fastService); 时,如果您在快速服务中引用 this 上下文,它不会是服务实例。

【讨论】:

  • 谢谢 - 非常有帮助 - 加上 Yaak 的意见,我已经开始工作了。你能解释一下 Zack Patterson 的评论(我也注意到了)“fastService 返回 'result' 作为名称而不是说名称未定义”?如果.then用于promise,并且调用的第一个函数(slowService)有一个延迟对象,浏览器怎么能简单地跳过延迟对象——不管@ 987654333@ 括号? fastService 输出 result 而不是 undefined 的事实似乎浏览器知道它应该期待一个承诺 result,但只是不等待它......
  • PS 也感谢关于 $timeout 的提示 - 我实际上只在 slowService 中包含了一个超时作为模拟 $http 调用和 SQLite 本地数据库查询的一种方式。
  • 也只是一点 - 你说That is because you are executing the function fastService before slowService, - 你能解释一下吗?从控制台输出来看,slowService 肯定会在 before fastService 开始 - 只是fastService 不会等到slowService 完成后才开始......对吗?
  • 讨厌我的英语我在声明的末尾清除了它,说在慢速服务的异步回调执行之前。 IL 更新该声明。我知道你在演示中使用超时,这就是我添加最后一条语句的原因。处理已经返回承诺的服务时,无需创建延迟对象。是的,从 q 承诺回调中,你可以返回数据或另一个承诺,最终解决的数据是你将在链中得到的结果。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    由于您的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

    【讨论】:

    • 感谢这一点-非常清楚-尽管正如@Zack Patterson 指出的那样,fastService 将“结果”作为名称返回,而不是说名称未定义-您知道这是为什么吗?就像.then 知道它应该期待一个承诺,但只是不等待它......
    • @goredwards 您传递给Service_1.fastFunctionname 变量并未在代码中的任何位置声明,因此当您调用Service_1.fastFunction(name) 时,您传递的是global name variable。 jsfiddle 代码在名为“result”的窗口内运行,这就是您看到“result”的原因。尝试传递一个不是全局定义的变量,你会看到一个非常不同的结果:jsfiddle.net/de8fn1vd/5
    【解决方案4】:

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

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

    只是为了澄清一下我很确定正在发生的事情:

    then 函数正在为 promise 被解决或被拒绝时注册回调。您不需要传递函数参数,因为当您 resolve 使用您尝试传递给回调函数的任何数据时,这已经完成了。当您在其中有 fastService(name) 时,它只是在遇到该行代码时立即执行该函数,而无需等待 Promise 解决,因为它是一个函数调用,而不是一个函数对象。

    有趣的是,fastService 将“结果”作为名称返回,而不是说名称未定义。我不知道它从哪里获取该变量的值。

    【讨论】:

      猜你喜欢
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 2015-03-27
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      相关资源
      最近更新 更多