2015-01-09 48 views
2

努力让承诺在angularjs服务提供商 正常工作,我读过docs以及无数的例子(hereherehere),我想我已经得到了我的语法确定 (虽然显然什么是错的)angularjs延期承诺不推迟

应用模块和控制器的样子

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

编辑:把快捷功能的服务,以便有一个与吊装等不会产生混淆 - 仍然是同样的结果 - 爵士小提琴更新

+0

它似乎setTimout稍后执行http://jsfiddle.net/q4vofnz8/18/ – sbaaaang 2015-01-09 20:15:50

+0

这里使用事件的例子http://jsfiddle.net/q4vofnz8/21/ – sbaaaang 2015-01-09 20:24:06

回答

5

的slowService完成

那是因为你正在执行slowService异步回调之前的功能fastService runs.Instead你想提供前fastService开始该函数的参考。即.then(Service_1.fastService(name));应该是.then(Service_1.fastService);.then(function(name){ Service_1.fastService(name); });,否则快速服务将在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上下文,则它不会是服务实例。

+0

谢谢 - 非常有帮助 - 与Yaak的输入一起我已经得到它的工作。你能解释一下Zack Patterson的评论(我也注意到)“fastService返回结果'作为名称而不是说名称是未定义的吗?如果仅将'.then'用于承诺,并且第一个名为('slowService')的函数具有延迟对象,那么浏览器如何简单地忽略延迟对象 - 无论“.then()”括号中的内容如何? 'fastService'输出'result'而不是'undefined'似乎就像浏览器知道它应该期待promise'result',但不会等待它... – goredwards 2015-01-09 23:40:50

+0

PS感谢$ timeout的提示 - 我实际上只在'slowService'中包含了一个超时作为模拟$ http调用和SQLite本地数据库查询的方式。 – goredwards 2015-01-09 23:42:45

+0

也只是一个观点 - 你说'那是因为你在slowService之前执行fastService函数, - 你能解释一下吗?从控制台输出中,'slowService'肯定会启动_before_'fastService' - 只是'fastService'不会等到'slowService'完成之后才开始......正确的吗? – goredwards 2015-01-09 23:48:35

2

你是通过你的函数的方式then()部分不正确。 通这样的:

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

哇 - 那么简单? – goredwards 2015-01-09 20:19:03

1

由于您的slowServicename的值解决,这就是将作为您传递给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

+0

非常感谢 - 尽管正如@Zack Patterson指出的那样,'fastService'返回'result'作为名称,而不是说该名称是未定义的 - 你知道这是为什么吗?这就像'.then'知道它应该期待一个承诺,但只是不等它... – goredwards 2015-01-09 23:31:50

+0

@goredwards你传递给'Service_1'的'name'变量。fastFunction'没有在代码中的任何地方声明,所以当你调用'Service_1.fastFunction(name)'时,你传递了[global'name'变量](https://developer.mozilla.org/en-US/文档/网络/ API/Window.name)。 jsfiddle代码在名为“result”的窗口中运行,所以这就是为什么你看到“result”。尝试传递一个不是全局定义的变量,你会看到一个非常不同的结果:http://jsfiddle.net/de8fn1vd/5/ – JLRishe 2015-01-10 05:49:24

+0

啊 - 有道理 - 谢谢! – goredwards 2015-01-10 07:18:19

1

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

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

只是为了澄清什么我敢肯定一点是怎么回事:

then函数注册回调时承诺要么解决或被拒绝。您不需要传递函数参数,因为当您尝试传递给回调函数的任何数据时,您已经完成了该操作。当你有fastService(name)时,它只要执行函数,只要它到达那行代码而没有等待解析的承诺,因为它是一个函数调用,而不是函数对象。

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