Как передать данные URL-адреса службы в функцию, где она вызывается контроллером

Я пытаюсь получить некоторые данные из URL-адреса, сохранить их в переменной и вернуть в свой контроллер. Но проблема в том, что данные из URL обрабатываются после того, как переменная уже возвращена контроллеру (который вызывает функцию). Я вызываю URL-адрес службы в своем Service.js. Вот как я это делаю:

var demoService = angular.module('demoService', []).service('myService', function($http, $q) {
    var gaugeData = {
        maxValue: 5000,
        animationSpeed: 100,
        val: 5000
    };

    console.log(gaugeData);

    var deferred = $q.defer();
    $http.get('http://myurl').then(function(data) {
        console.log(data.data.Tweets[3].FAVOURITE_COUNT);
        var gaugeData = {
            maxValue: 5000,
            animationSpeed: 100,
            val: data.data.Tweets[3].FAVOURITE_COUNT
        };
        deferred.resolve(gaugeData);
        console.log(gaugeData);
    });

    this.get = function() {
        deferred.promise.then(function(data) {
            console.log(data);
            gaugeData.val = data.val;
        });
        return gaugeData;
    };

    function sleep(milliseconds) {
        var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
            if ((new Date().getTime() - start) > milliseconds) {
                break;
            }
        }
    }

    this.list = function() {
        return gaugeData;
    };

});

Контроллер ожидает данные в той же форме, что и объект gaugeData, но поскольку gaugeData заполняется служебными данными после того, как значение уже возвращено, контроллер не показывает объект (undefined). Консоль выглядит так:

    Object {maxValue: 5000, animationSpeed: 100, val: 5000}
    controllers.js:202 $…t.l.$…w.a.$…e.$$ChildScope {$$childTail: null, $$childHead: null, $$nextSibling: null, $$watchers: null, $$listeners: Object…}   (console.log); from controller 
    app.js:15 TypeError: Cannot read property 'maxValue' of undefined (since an empty value is passed)
       1566
   services.js:137 Object {maxValue: 5000, animationSpeed: 100, val: 1566}
   services.js:144 Object {maxValue: 5000, animationSpeed: 100, val: 1566}

Ясно, что элемент управления сначала входит в службу, а затем во время обработки URL-адреса элемент управления переходит к элементу управления и принимает пустое значение, и после того, как это произошло, URL-адрес обрабатывается, и gaugeData заполняется значениями из URL-адреса службы. Я попытался сделать это без обещания и отложил. Я просто использовал $http.get(url).success(function(){code});

Как я могу передать свои данные URL в переменную и правильно передать их контроллеру в нужное время?

Также вот фрагмент кода моего контроллера, где я вызываю сервисную функцию:

console.log($scope);
return $scope.gaugeHome ={
         gaugeData:
             myService.get(), .....

person rawatdeepesh    schedule 27.05.2015    source источник
comment
this внутри then - это объект окна, это ошибка в строгом режиме - запустите свой код в строгом режиме :)   -  person Benjamin Gruenbaum    schedule 27.05.2015
comment
@BenjaminGruenbaum — у автора на самом деле нет this внутри then. Просто был плохой отступ (сейчас исправлено). ;-)   -  person Gabriel L.    schedule 28.05.2015


Ответы (1)


  1. Не заключайте существующие обещания в новые отсрочки; это антипаттерн. $http уже возвращает промис, который вы можете изменить, return добавив новые промисы или значения из then обработчиков.

  2. Вы не можете вернуть значение синхронизации, являющееся результатом асинхронной операции. Это фундаментальное противоречие в терминах. Если вам нужно вернуть что-то, что в конечном итоге будет установлено в значение, в этом весь смысл промиса. Ваша служба должна вернуть обещание, которое затем ваш контроллер вызовет then.

  3. Ваша функция sleep вызывает беспокойство. Похоже, вы используете петлю занятости, чтобы… что делать? Повесить процессор на время? Почему? А почему не просто $timeout?

Вот версия вашей службы, которая A) извлекает ресурс один раз, B) сохраняет его в обещании и C) позволяет потребителям (контроллерам) запрашивать обещание. Затем контроллеры должны будут вызвать then, чтобы решить, что делать с результатом.

Если вы хотите, чтобы ваш сервис мог обновлять ресурс, вы можете обернуть генерацию промиса в функцию, которая снова запускает выборку и возвращает новый промис. Однако не совсем понятно, какова ваша конечная цель, поэтому я не показывал этот подход.

var demoService = angular.module('demoService', []).service('myService', function($http, $q) {

    var gaugePromise = $http.get('http://myurl').then(function(response) {
        var updatedGuageData = {
            maxValue: 5000,
            animationSpeed: 100,
            val: response.data.Tweets[3].FAVOURITE_COUNT
        };
        return updatedGuageData;
    });

    this.get = function() {
        return gaugePromise;
    };

});

Теперь вы можете заставить службу кэшировать значение как синхронный объект (в соответствии с тем, что вы пытались сделать), и всякий раз, когда вы асинхронно получаете его, обновлять кеш как побочный эффект (как вы делает). Однако каждый раз, когда вы выполняете асинхронное обновление, единственный раз, когда вы можете узнать, что оно успешно (или не удалось), — это использовать обработчик обратного вызова или обещания, что делает кешированное синхронное значение бессмысленным — почему бы просто не использовать результаты асинхронный напрямую? Гораздо проще.

person Gabriel L.    schedule 28.05.2015