在我的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
不会更新,我的测试观察者也不会更新。
当我刷新页面时,有时会使用登录的consumerUrl,有时则不会 我猜测有时候会话恢复首先发生,有时行动电缆服务首先发生。
首先加载动作有线电视服务时,我期望发生的是:
currentUser.user
(发生这种情况,我可以在我的页面上看到用户名)consumer
计算属性会通知currentUser.user
更改并连接到私有consumerUrl(不会发生)我可以很容易地以不依赖于计算属性的方式解决这个问题,但我想知道这里出了什么问题。
答案 0 :(得分: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();
},
操作有线服务从currentService
读取属性,设置consumerUrl
,并调用电缆服务来创建消费者:< / p>
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来演示。
答案 1 :(得分:1)
另一种方法是在服务中发出event,然后在init方法中订阅该事件,并设置计算属性的依赖键的值,以强制重新计算/更新它。 / p>