Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
125 views
in Technique[技术] by (71.8m points)

javascript - Am I returning this promise correctly?

I have a function, getMonitors inside a service. getMonitors returns a list of monitor objects. If the monitor object is empty, it grabs the monitors via http and stores the objects in a monitor object array and then returns it. The function is coded as a promise. I know http returns a promise, but my function may or may not use http - so I've overlaid it with my own promise (see below for code)

Controllers can call getMonitors(0) or getMonitors(1). 0 means if its already loaded in the monitors array due to a previous call, don't load it again. (1) means force reload the array from HTTP

The service and associated getMonitors is coded the following way:

angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q',
      function($http, $q) {
        // var deferred='';
        var monitorsLoaded = 0;
        var monitors = [];

        getMonitors: function(forceReload) {
          console.log("** Inside ZMData getMonitors with forceReload=" + forceReload);
          var d = $q.defer();
          if ((monitorsLoaded == 0) || (forceReload == 1)) // monitors are empty or force reload
          {
            console.log("ZMDataModel: Invoking HTTP Factory to load monitors");
            var apiurl = loginData.apiurl;
            var myurl = apiurl + "/monitors.json";
            $http.get(myurl)
              .success(function(data) {
                // console.log ("HTTP success got " + JSON.stringify(data));
                monitors = data.monitors;
                console.log("promise resolved inside HTTP success");
                monitorsLoaded = 1;
                return d.resolve(monitors);
              })
              .error(function(err) {
                console.log("HTTP Error " + err);
                monitors = [];
                console.log("promise resolved inside HTTP fail");
                // I know I need to reject here, not resolve. I'll get to it. For now lets assume I need an empty monitors list if there was an error
                return d.resolve(monitors);
              });
            console.log("promise deferred inside HTTP inside getMonitors");
            return d.promise;

          } else // monitors are loaded
          {
            console.log("Returning pre-loaded list of " + monitors.length + " monitors");
            return d.resolve(monitors);
          }

        },

I have a route set up with getMonitors as a dependency like so:

.state('app.montage', {
  data: {
    requireLogin: false
  },
  resolve: {
    message: function(ZMDataModel) {
      console.log("Inside app.montage resolve");
      return ZMDataModel.getMonitors(0);
    }
  },
  url: "/montage",
  views: {
    'menuContent': {
      templateUrl: "templates/montage.html",
      controller: 'zmApp.MontageCtrl',


    }
  }
})

A sample controller that uses this is coded like so:

angular.module('zmApp.controllers').controller('zmApp.MontageCtrl', function($scope, $rootScope, ZMDataModel, message) {

  $scope.monitors = [];
  console.log("Inside MontageCtrl waiting for monitors to load...");

  $scope.monitors = message;
  // this line returns undefined when getMonitors tries to return a preloaded monitor list
  console.log("I have received the monitors inside Montage and there are " + $scope.monitors.length);
  // console.log("***CALLING FACTORY");
  //ZMHttpFactory.getMonitors().then(function(data) //{
  //                                  $scope.monitors = data;
  // console.log("I GOT " + $scope.monitors);
  //    });

  $scope.doRefresh = function() {
    console.log("***Pull to Refresh");
    $scope.monitors = [];

    var refresh = ZMDataModel.getMonitors(1);
    refresh.then(function(data) {
      $scope.monitors = data;
      $scope.$broadcast('scroll.refreshComplete');
    });

  };
});

The problem I am facing is that the first time this is run, the monitors list is empty so ZMData loads the monitors from the HTTP url and the view shows perfectly. When I switch to another view and back to this view, I see it logs that ZMData is returning the preloaded list of monitors (I know they are populated because I am printing out the count in ZMData getMonitor else section). However, what is being returned to the controller is undefined when the "else" part of getMonitors hit.

This likely means I am not returning the promise correctly in getMonitors "else" part.

Any help would be appreciated

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Ah, I finally wrapped my head around promises. We can't return d.resolve(). That just sets a state. You always need to return d.promise and it if was resolved, it will return the resolve. Man. This drove me mad.I think I finally got the basic hang of promises after 3 different SO questions. I wish tutorials made this clearer. Everyone was only returning d.promise and no one really explained clearly that d.promise returns the state of the promise - which is changed by resolve or reject.

The correct code is:

getMonitors: function (forceReload) {
            console.log ("** Inside ZMData getMonitors with forceReload="+forceReload);
            var d = $q.defer();
           if ((monitorsLoaded == 0) || (forceReload == 1)) // monitors are empty or force reload
           {
               console.log ("ZMDataModel: Invoking HTTP Factory to load monitors");
                var apiurl = loginData.apiurl;
                var myurl = apiurl+"/monitors.json";
                $http.get(myurl)
                    .success(function(data)
                    {
                       // console.log ("HTTP success got " + JSON.stringify(data));
                        monitors = data.monitors;
                        console.log ("promise resolved inside HTTP success");
                        monitorsLoaded = 1;
                        d.resolve(monitors);
                    })
                    .error (function (err)
                    {
                        console.log ("HTTP Error " + err);
                        monitors = [];
                        console.log ("promise resolved inside HTTP fail");
                        d.resolve (monitors);
                });
                return d.promise;

           }
            else // monitors are loaded
            {
                console.log ("Returning pre-loaded list of "+monitors.length+" monitors");
                 d.resolve(monitors);
                return d.promise;
            }

        }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...