2015-01-09 2 views
2

изо всех сил, чтобы получить обещания правильно работающих в angularjs поставщика услуг я читал docs, а также многочисленные примеры (here, here и here) и я думаю, что у меня есть мой синтаксис нормально (хотя явно что-то не так)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 

fastService начинает перед slowService Завершает, несмотря на использование отложенный объект/обещание в Service_1.then и в контроллере ...

Может ли кто-нибудь указать, что не так с кодом?

jsfiddle является here

EDIT: поставить быструю функцию в обслуживании, так что нет никакой путаницы с грузоподъемными и т.д. - все тот же результатом - JS скрипка обновленного

+0

кажется setTimout выполнен позже http://jsfiddle.net/q4vofnz8/18/ – sbaaaang

+0

здесь пример с использованием событий http://jsfiddle.net/q4vofnz8/21/ – sbaaaang

ответ

5

fastService начинается до того, как slowService завершает

Это потому, что вы выполняете функцию fastService перед тем slowService обратного вызова runs.Instead асинхронные вы хотите, чтобы обеспечить ссылка на функцию. i.e .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);, и если вы ссылаетесь на контекств быстрой службе, он не будет экземпляром службы.

+0

спасибо - очень полезно - вместе с входом Яака у меня это работает. Можете ли вы объяснить замечание Зака ​​Паттерсона (что я также заметил), что «fastService возвратил результат» как имя вместо того, чтобы сказать, что имя не определено »? Если '.then' _only_ используется для обещаний, а первая функция (' slowService') имеет отложенный объект, как браузер может просто пропускать отложенный объект - независимо от того, что находится в скобках '.then()' ? Тот факт, что 'fastService' выдает' result' вместо 'undefined', похоже, что браузер знает, что он должен ожидать обещания' result', но просто не дождался его ... – goredwards

+0

PS спасибо также за подсказки в $ timeout - Я фактически включил тайм-аут в 'slowService' как способ моделирования $ http-вызовов и запросов SQLite localdatabase. – goredwards

+0

также просто точка - где вы говорите «Это потому, что вы выполняете функцию fastService до slowService», - можете ли вы это объяснить? С выхода консоли, 'slowService' определенно запускается _before_' fastService' - это просто то, что 'fastService' не дожидается, пока' slowService' не закончит, прежде чем начать ... правильно? – goredwards

2

, как вы передаете вашу функцию then() часть неправильный. Pass это так:

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

wow - это просто? – goredwards

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.

+0

спасибо за это - очень понятно - хотя, как указывает @Zack Patterson, 'fastService' вернул« результат »в качестве имени вместо того, чтобы сказать, что это имя не определено - знаете ли вы, почему это так? Это похоже на '.then', потому что знает, что он должен ожидать обещания, но просто не дождался его ... – goredwards

+0

@goredwards Переменная' name', которую вы передаете 'Service_1.fastFunction' не объявляется нигде в вашем коде, поэтому, когда ваш вызов 'Service_1.fastFunction (name)', вы передаете переменную [global 'name'] (https://developer.mozilla.org/en-US/ документы/Web/API/Window.name). Код jsfiddle запускается внутри окна с именем «результат», поэтому вы видите «результат». Попробуйте передать переменную, которая не определена глобально, и вы увидите совсем другой результат: http://jsfiddle.net/de8fn1vd/5/ – JLRishe

+0

ah - имеет смысл - спасибо! – goredwards

1

YAAK правильный. Вы также можете написать это:

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

Просто чтобы прояснить немного о том, что я уверен, что происходит:

then функция регистрации обратных вызовов, когда обещание либо решённые или отклонено. Вам не нужно передавать параметры функции, потому что это уже сделано, когда вы resolve с любыми данными, которые вы пытаетесь передать функции обратного вызова. Когда у вас было fastService(name), он просто выполнял функцию, как только попадал в эту строку кода, не дожидаясь, пока обетование будет разрешено, поскольку это вызов функции, а не объект функции.

Интересно, что fastService возвратил 'result' как имя вместо того, чтобы сказать, что это имя не определено. Я не знаю, откуда он получает значение для этой переменной.