Javascript 一个计算出的;“睡觉”;直到一些初始化完成

Javascript 一个计算出的;“睡觉”;直到一些初始化完成,javascript,knockout.js,Javascript,Knockout.js,我有一个复杂的viewmodel,它包含几个可观察属性、数组等。我有一个计算的可观察属性,它有几个依赖项。在定义时不能执行计算的内部逻辑,而只能在模型完全初始化之后执行 例如: 图像用户可以从多个大陆、国家或城市中选择一个的表单。每次选定某些大陆时,国家列表应仅包含位于选定大陆上的国家,城市等也应如此 为了优化HTTP流量,初始列表作为页面的一部分填充,因此不需要初始JSON请求 var viewModel = function(data) { this.Continents = ko.ob

我有一个复杂的viewmodel,它包含几个可观察属性、数组等。我有一个计算的可观察属性,它有几个依赖项。在定义时不能执行计算的内部逻辑,而只能在模型完全初始化之后执行

例如:

图像用户可以从多个大陆、国家或城市中选择一个的表单。每次选定某些大陆时,国家列表应仅包含位于选定大陆上的国家,城市等也应如此

为了优化HTTP流量,初始列表作为页面的一部分填充,因此不需要初始JSON请求

var viewModel = function(data) {
  this.Continents = ko.observableArray(data.Continents);
  this.Countries = ko.observableArray(data.Countries);
  this.Cities = ko.observableArray(data.Cities);

  this.SelectedContinents = ko.observableArray(data.SelectedContinents);
  this.SelectedCountries = ko.observableArray(data.SelectedCountries);
  this.SelectedCities = ko.observableArray(data.SelectedCities);

  this.LoadFromServer = function() {
    $.post({
      url: '/reloadLists',
      data: { continents: this.SelectedContinents(), countries: this.SelectedCountries(), cities: this.SelectedCities() },
      success: function(result) {
        this.Continents(result.Continents);     
        this.Countries(result.Countries);
        this.Cities(result.Cities);
      } 
    });
  };

  ko.computed(function() {
    this.LoadFromServer();
  }, this);

}

...

var data = ... // initial data rendered on server-side 
var model = new viewModel(data);
ko.applyBindings(model);
使用这种方法,问题在于当computed最初执行rad函数时,LoadFromServer逻辑也会在模型初始化时执行。这样就有了冗余的往返,因为初始列表已经在模型中了

我现在能想到的唯一解决方案是引入一个标志来阻止具体的逻辑,直到需要它为止。这个标志不应该是可观察的,因为当我在构造函数末尾将它设置为true时,计算出的值将被重新计算,冗余的往返将再次进行。但是,如果该标志不是可观察的,那么我必须确保在初始化时捕获依赖项,以便它能够在之后对更改做出反应。把所有这些放在一起,currenct结果看起来像这样

var viewModel = function(data) {

  var initialized = false;

  this.Continents = ko.observableArray(data.Continents);
  this.Countries = ko.observableArray(data.Countries);
  this.Cities = ko.observableArray(data.Cities);

  this.SelectedContinents = ko.observableArray(data.SelectedContinents);
  this.SelectedCountries = ko.observableArray(data.SelectedCountries);
  this.SelectedCities = ko.observableArray(data.SelectedCities);

  this.LoadFromServer = function() {
    $.post({
      url: '/reloadLists',
      data: { continents: this.SelectedContinents(), countries: this.SelectedCountries(), cities: this.SelectedCities() },
      success: function(result) {
        this.Continents(result.Continents);     
        this.Countries(result.Countries);
        this.Cities(result.Cities);
      } 
    });
  };

  ko.computed(function() {
    var catchDependencies = [this.SelectedContinents(), this.SelectedCountries(), this.SelectedCities()];
    if (!initialized) return;
    this.LoadFromServer();
  }, this);  

  initialized = true;
}
从技术上讲,这是一个很好的解决方案,但我不太喜欢它,因为它对我来说有些味道


对于这些场景,有没有更好的解决方案?或者我不应该尝试优化事情,让初始AJAX加载,而不是服务器端的initialo数据呈现?

嗨,我不确定这是否是最好的方法,但它可以工作

所以我的方法是,我创建了一个名为
isComplete
的标志,如果这是真的,那么显示计算值,否则显示默认值。这适用于HTML,以便绑定不会失败

此外,我还添加了一个按钮,用于注册计算值。它也可以在订阅某个值时执行此操作

var ViewModel=函数(第一个,最后一个){
var self=这个;
self.firstName=ko.可观察(第一);
self.lastName=ko.可观察(last);
self.isComplete=ko.可观察(假);
//计算注册部分
self.registerComputed=函数(){
如果(!self.hasOwnProperty(“全名”)){
self.fullName=ko.computed(函数(){
返回此.firstName()+“”+此.lastName();
},这个);
}
self.isComplete(真);
}
};
ko.应用绑定(新视图模型(“行星”、“地球”)
body{font-family:arial;字体大小:14px;}
.liveExample{填充:1em;背景色:#eeedd;边框:1px实心#CCC;最大宽度:655px;}
.liveExample输入{font-family:Arial;}
.liveExample b{font-weight:bold;}
.liveExample p{页边距顶部:0.9em;页边距底部:0.9em;}
.liveExample选择[多个]{宽度:100%;高度:8em;}
.liveExample h2{页边空白:0.4em;字体重量:粗体;字体大小:1.2em;}

名字:

姓氏:

你好
嗨,我不确定这是否是最好的方法,但它确实有效

所以我的方法是,我创建了一个名为
isComplete
的标志,如果这是真的,那么显示计算值,否则显示默认值。这适用于HTML,以便绑定不会失败

此外,我还添加了一个按钮,用于注册计算值。它也可以在订阅某个值时执行此操作

var ViewModel=函数(第一个,最后一个){
var self=这个;
self.firstName=ko.可观察(第一);
self.lastName=ko.可观察(last);
self.isComplete=ko.可观察(假);
//计算注册部分
self.registerComputed=函数(){
如果(!self.hasOwnProperty(“全名”)){
self.fullName=ko.computed(函数(){
返回此.firstName()+“”+此.lastName();
},这个);
}
self.isComplete(真);
}
};
ko.应用绑定(新视图模型(“行星”、“地球”)
body{font-family:arial;字体大小:14px;}
.liveExample{填充:1em;背景色:#eeedd;边框:1px实心#CCC;最大宽度:655px;}
.liveExample输入{font-family:Arial;}
.liveExample b{font-weight:bold;}
.liveExample p{页边距顶部:0.9em;页边距底部:0.9em;}
.liveExample选择[多个]{宽度:100%;高度:8em;}
.liveExample h2{页边空白:0.4em;字体重量:粗体;字体大小:1.2em;}

名字:

姓氏:

你好
试试看

阅读更多

试试看


阅读更多

您需要使用的是
延迟评估
选项:

可选。如果此选项为true,则在某个对象实际尝试访问其值或手动订阅该值之前,不会计算计算出的可观测值。默认情况下,在创建过程中,计算的可观察对象的值会立即确定

Te idea正在设置此选项,并在初始化完成时手动访问可观察对象,使其“变为活动”。当然,您必须将其存储在“private”变量中才能访问它


另请参见:

您需要使用的是
延迟评估
选项:

可选。如果此选项为true,则在某个对象实际尝试访问其值或手动订阅该值之前,不会计算计算出的可观测值。默认情况下,在创建过程中,计算的可观察对象的值会立即确定

Te idea正在设置此选项,并在初始化完成时手动访问可观察对象,使其“变为活动”。当然,您必须将其存储在“private”var中
ko.computed(function() {
  if(ko.computedContext.isInitial()) return;
  this.LoadFromServer();
}, this);
  this.SelectedContinents.subscribe(this.LoadFromServer);
  this.SelectedCountries.subscribe(this.LoadFromServer);
  this.SelectedCities.subscribe(this.LoadFromServer);