AngularJS承诺的功能范围

时间:2014-05-28 18:39:14

标签: angularjs

我在AngularJS中理解承诺时遇到了问题。

我有以下内容:

var loader = angular.module('loadIt', []);

loader.factory('loadService', function($http, $q) {
  return {
    getJs: function(path) {
      var deferred = $q.defer();

      $http.get(path).then(function(response) {
        deferred.resolve(response.data);
      });

      return deferred.promise;
    }
  }
});

var myMod = angular.module('myMod', ['loadIt']);

myMod.service('mymodService', function(loadService) {

  this.vals = {};
  this.readIt = function (pos) {
            this.vals[pos] = loadService.getJs('aaa.js');
  }

});

在调试器中,我看到了这一行:

this.vals[pos] = loadService.getJs('aaa.js');

getJs()调用返回正确的值。 但范围是错误的。 this.vals未在readIt函数内定义。 我该如何解决这个问题?

修改

我也尝试了以下内容:

  this.readIt = function (pos) {
     loadService.getJs('aaa.js').then(function(data) {
        this.vals[pos] = data;
    });
  }

在这里,我看到数据包含从文件中读取的JSON对象。

这指的是对象Window,this.vals在范围内不存在。

2 个答案:

答案 0 :(得分:2)

由于您选择使用服务(而不是工厂),因此您需要将this分配给另一个变量(通常为self,如下所示),如果您希望从另一个功能的范围。否则,this回调函数中then的上下文发生变化的事实是有问题的。

myMod.service('mymodService', function(loadService) {
  this.vals = {};
  var self = this;

  this.readIt = function (pos) {
    loadService.getJs('aaa.js').then(function(data){
      self.vals[pos] = data;
    });
  }
});

使用上面的代码,您可以设置范围变量,如下所示:

myMod.controller('MyController', function($scope, mymodService, $timeout){
  mymodService.readIt(0);
  $scope.vals = mymodService.vals;
})

如果您发现此方法最初不适合您,请将this demo与您的代码进行比较,并考虑您可能需要重构的内容。

附加说明:

如果您不喜欢var self = this语法,请考虑使用工厂而不是服务:

myMod.factory('mymodService', function(loadService) {
  var modservice = {
    vals: {}
  };

  modservice.readIt = function (pos) {
    loadService.getJs('aaa.js').then(function(data){
      modservice.vals[pos] = data;
    });
  }

  return modservice;
});

Demo

答案 1 :(得分:2)

这里有2个潜在问题。

1)loadService.getJs()返回一个承诺。因此,您要为this.vals[pos]分配承诺,而不是实际值。假设您想要分配实际值,那么您需要

loadService.getJs().then(function(data) {
      this.vals[pos] = data;
  });   

2)this指的是调用上下文。所以在readIt() this中将引用任何称为它的对象 - 而不是它在(在这种情况下为mymodService)中定义的词法范围。但您可以使用bind()来解决此问题。 bind允许我们强制执行函数时绑定的this。因此,在回调结束时添加bind(),您的代码现在看起来像:

this.vals = {};
this.readIt = function (pos) {
  loadService.getJs().then(function(data) {
      this.vals[pos] = data;
  }.bind(this));   
}

this可能会非常棘手 - 如果您想了解更多细节,可以结帐this blog by Dan Wahlin

这是一个精简版fiddle,其中包含两项更改,显示所有内容都在视图$ scope中连接。