我正在尝试找出运行长时间运行加载操作的最佳位置是使用Durandal。
据我所知,加载数据的一般建议是在ViewModel的activate
方法中,这就是我通常所做的事情 - 例如:
viewModel.activate = function () {
var loadPromise = myService.loadData();
return $.when(loadPromise).then(function (loadedData) {
viewModel.data(data);
});
};
我知道如果我不在这里回复承诺,那么绑定通常会出现问题 - this question and answer indicates。
但是,在activate
方法中执行长时间运行的加载操作会使加载操作完成时应用程序“冻结”。例如,如果我的负载现在是这样的呢?
viewModel.activate = function () {
// All loads return a promise
var firstLoad = myService.loadFirstData();
var secondLoad = myService.loadSecondData();
var thirdLoad = myService.loadThirdDataWhichTakesAges();
return $.when(firstLoad, secondLoad, thirdLoad).then(function (one, two, three) {
viewModel.one(one);
viewModel.two(two);
viewModel.three(three);
});
};
在这种情况下,URL会更新以反映正在加载的页面,但页面内容仍然显示上一页(我的意思是“冻结”)。
理想情况下,如果URL应更改为新页面,并且页面内容也应显示新页面(即使尚未返回该页面的数据),也会很好。然后,当每个加载操作返回时,应在数据绑定到视图模型时更新页面的相关部分。
是否有推荐的方法在Durandal中实现这一目标?
我目前的解决方案是在activate
方法中启动加载,然后使用viewAttached
方法填充数据:
var loadPromise;
viewModel.activate = function () {
// All loads return a promise
var firstLoad = myService.loadFirstData();
var secondLoad = myService.loadSecondData();
var thirdLoad = myService.loadThirdDataWhichTakesAges();
loadPromise = $.when(firstLoad, secondLoad, thirdLoad);
// Don't return the promise - let activation proceed.
};
viewModel.viewAttached = function () {
$.when(loadPromise).then(function (one, two, three) {
viewModel.one(one);
viewModel.two(two);
viewModel.three(three);
});
};
似乎 工作,但我记得在某处依赖viewAttached
并不是一个好的解决方案。我也不确定是否存在竞争条件,因为我允许激活继续进行。
还有其他建议吗?
答案 0 :(得分:8)
您不必返回承诺,但在这种情况下,您必须在敲除绑定中处理此问题,因此您不会绑定到未定义的元素。您可以尝试在激活中删除“返回”,但添加一个属性,指示模型是否仍在加载。像这样:
viewModel.isLoading = ko.observable(false);
viewModel.activate = function () {
isLoading(true);
var loadPromise = myService.loadData();
$.when(loadPromise).then(function (loadedData) {
viewModel.data(data);
isLoading(false);
});
};
然后,在您的视图中,您可以在视图仍在加载时显示一个部分,在加载完成时显示一个部分。有些人喜欢:
<div data-bind:"visible: isLoading()">Loading Data....</div>
<div data-bind:"visible: !isLoading()">Put your regular view with bindings here. Loading is done so bindings will work.</div>
答案 1 :(得分:0)
您使用的是哪个版本的Durandal?在Durandal 2.0.0pre中,您将不允许在activate
中返回一个承诺,以便视图的组成(没有数据)可以立即发生。
您可以考虑将viewModel.one
等重构为返回构造函数的模块,以便每一个,两个,三个负责检索自己的数据。这样你前两个电话就不必等loadThirdDataWhichTakesAges
。在一,二,三不相互依赖的情况下,这是有意义的。
答案 2 :(得分:0)
供参考;我在Durandal Google Group上发布了一个类似的问题(有效地询问是否以这种方式使用activate和viewAttached是一个好主意)并得到Rob Eisenberg的回复:
这可能会奏效。问题是Knockout会破坏 如果属性更新和元素,则对元素进行数据绑定 目前不在文件中。这可能发生取决于 异步代码的时间。因为组合的方式 1.x,如果您没有从激活功能返回承诺,这将导致问题。它应该在viewAttached中更好地工作,但是 根据您的作品的性质,可以附上视图 到它的父母,但仍然没有在文件中。这取决于深度 的组成。所以,如果你也可能遇到问题 你有一个深度组合的模块。不幸的是,没有 由于淘汰行为,在Durandal 1.x中一个干净的方式。在 Durandal 2.x我们已经重新设计了这个问题 不存在并且不再需要返回承诺(尽管如此 你仍然可以这样做)。 Durandal 2.0将在大约两个版本中发布 周。