2015-01-09 47 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'作爲名稱,而不是說該名稱未定義。我不知道它從哪裏獲得該變量的值。