两个控制器依赖于异步返回的相同数据

Two controllers depending on same data returned asynchronously

有一个允许用户创建或加入房间的应用程序。因此 RoomsListController 显示房间,RoomDetailsController 显示特定房间内 activity 的内容和控件。当然,RoomService 提供了 getRooms()(异步)方法。

现在 Angular 使两个控制器等待 RoomService.getRooms() 返回的相同数据的方法是什么?

详情:

看看route resolve promises

您将在路由解析之前调用异步方法

// in your config
$routeProvider.when('/your-route', {
  resolve: {
    roomData: function(RoomService) {
      return RoomService.getRooms();
    }
  }
}

// RoomsListController
function(roomData) {
  // do something with roomData
}

// RoomDetailsController
function(roomData) {
  // do something with roomData
}

这样,就控制器而言,数据甚至在路由加载之前就已经存在。

您谈到了一个关键问题是应用程序...也就是说,为以应用程序可以使用的方式组合的数据创建单一真实来源。

有很多模式可以解决这个问题,但我建议先看看路由解析承诺,然后再从那里扩展。它可以变得非常复杂。

另一种方法可能是修改服务中的 RoomService.getRooms() 函数,以便在您等待来自服务器的结果时,在首次调用该函数时声明和存储本地承诺。如果再次调用该函数,您将立即 return 相同的承诺。从服务器 return 获取结果后,您可以解决存储的承诺并清除它,因此下次调用它时,将发出新请求。

当然,这里有足够的自定义空间。如果您知道来自服务器的数据永远不会改变,例如,您根本不需要清除承诺。每次有人要房间时,只需 return 即可。

这是一个示例实现:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, RoomService) {
  $scope.name = 'World';

  $scope.fetchingStatus = function() {
    return RoomService.serverRequests ? 'Fetching... Server Requests: ' + RoomService.serverRequests : '';
  };

  $scope.getRooms = function() {
    console.log('asking for rooms')
    RoomService.getRooms().then(function(rooms) {
      console.log('rooms returned: ', rooms);
      $scope.rooms = rooms;
    });
  };
});

function RoomService($q, $timeout) {
  this.$q = $q;
  this.$timeout = $timeout;
  this.getRoomsPromise = null;
  this.serverRequests = 0;
}

RoomService.prototype.getRooms = function() {
  if (!this.getRoomsPromise) {
    this.getRoomsPromise = this.$q.defer();
    this.getRoomsFromServer();
  }
  return this.getRoomsPromise.promise;
};

RoomService.prototype.getRoomsFromServer = function() {
  var rooms = [];
  for (var i = 1; i <= 10; i++) {
    rooms.push({
      id: i,
      name: 'Room ' + i
    });
  }
  console.log('fetching data from server...');
  this.serverRequests++;
  this.$timeout(function() {
    this.serverRequests--;
    this.getRoomsPromise.resolve(rooms);
    this.getRoomsPromise = null;
    console.log('got data from server...')
  }.bind(this), 1500);
}

app.service('RoomService', RoomService);
.fetching {
  background-color: red;
  color: white;
  padding: 2px 10px;
  display: inline-block;
  margin-left: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
  <p>
    <button ng-click="getRooms()">Get Rooms</button>
    <span class="fetching" ng-show="fetchingStatus()">{{fetchingStatus()}}</span>
  </p>
  <ul>
    <li ng-repeat="room in rooms track by room.id">{{room.name}}</li>
  </ul>
</div>