В моем приложении Ember 2.8 я устанавливаю соединение Websocket в службе. URL-адрес подключения изменяется, когда пользователь входит в систему (затем он включает токен аутентификации пользователя в качестве параметра запроса).

Текущий пользовательский сервис прост:

CurrentUserService = Ember.Service.extend(
  name: "current-user"

  user: null

  load: ->
    // Do some stuff
    @set("user", user)
 )

Он работает точно так, как ожидалось, и я использую его для отображения имени пользователя текущего пользователя на странице (среди прочего).

В службе Websocket все, что я делаю, - это создаю вычисляемое свойство в зависимости от currentUser.user, которое устанавливает соединение (в зависимости от того, вошел ли пользователь в систему):

ActionCableService = Ember.Service.extend(
  name: "action-cable"

  cable: service()
  currentUser: service()

  testObs: Ember.observer("currentUser", ->
    console.log "currentUser changed, #{ @get("currentUser.user") }"
  )

  consumer: Ember.computed("currentUser.user", ->
     consumerUrl = "ws://localhost:10000/cable"

    if @get("currentUser").user?
      consumerUrl += "?token=#{ @get("currentUser.user.authToken") }"

    console.log(consumerUrl)
    return @get("cable").createConsumer(consumerUrl)
  ) 
)

Проблема в том, что потребительская собственность никогда не обновляется. Он устанавливается один раз при загрузке страницы, и когда свойство пользователя службы currentUser изменяется, consumer не обновляется, как и мой тестовый наблюдатель.

Когда я обновляю страницу, иногда используется пользовательскийUrl, а иногда - нет.
Я предполагаю, что иногда сначала происходит восстановление сеанса, а иногда - кабельная служба действий.

Я ожидал, что при первой загрузке кабельной службы действий произойдет следующее:

  1. Служба кабеля действий загружается, текущий пользователь еще не настроен, подключитесь к общедоступному веб-сокету
  2. Логика, которая обрабатывает восстановление пользователя из данных сеанса, срабатывает, устанавливает currentUser.user (это происходит, я вижу имя пользователя на своей странице)
  3. Вычисляемое свойство consumer замечает изменение currentUser.user и подключается к частному consumerUrl (не происходит)

Я могу очень легко решить эту проблему способом, который не зависит от вычисленных свойств, но я хотел бы знать, что здесь пошло не так.

2
Nils Landt 26 Ноя 2016 в 08:16

2 ответа

Лучший ответ

Вычисляемые свойства по умолчанию отслеживают любые изменения, внесенные в свойства, от которых они зависят, и динамически обновляются. когда им звонят .

Если вы не вызываете или не вызываете это вычисленное свойство, оно не выполнит ваш предполагаемый код.

Observers, с другой стороны, реагировать без вызов, когда свойство, которое они наблюдают, изменяется. Но ими часто злоупотребляют, и они могут легко привести к ошибкам из-за своей синхронной природы.

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

В своем контроллере вы можете выполнить начальное действие по входу в систему, например:

currentUser: Ember.inject.service(),

actions: {
  login() {
    this.auth({ username: 'Mary' });
  },
},

auth(data) {
  // Send data to server for authentication...

  // ...upon response, handle the following within the promise's `then`
  // method, failures caught within `catch`, etc. But for purposes of 
  // demonstration, just mocking this for now...
  const response = { username: 'Mary', authToken: 'xyz', };
  this.get('currentUser').setConsumer(response);
},

Затем служба текущего пользователя могла бы установить свои свойства и вызвать вспомогательную функцию для службы action-cable:

actionCable: Ember.inject.service(),

authToken: null,
username: null,

setConsumer(response) {
  this.set('authToken', response.authToken);
  this.set('username', response.username);
  this.get('actionCable').setConsumer();
},

Служба action-cable считывает свойства из currentService, устанавливает consumerUrl и вызывает службу cable для создания потребителя:

cable: Ember.inject.service(),
currentUser: Ember.inject.service(),

setConsumer() {
  var consumerUrl = "ws://localhost:10000/cable";

  if (this.get("currentUser.username") !== null) {
    consumerUrl += "?token=" + (this.get("currentUser.authToken"));
  }

  console.log("ACTION CABLE SERVICE, Consumer URL: ", consumerUrl);
  this.get("cable").createConsumer(consumerUrl);
}

Я создал Ember Twiddle для демонстрации.

3
jacefarm 26 Ноя 2016 в 08:09

Другой способ - создать в службе событие и затем подписаться к событию в методе инициализации и установите значение зависимого ключа вычисляемого свойства, чтобы принудительно вычислить / обновить его.

1
user8157522 20 Ноя 2017 в 23:13