我正在尝试找出运行长期加载操作的最佳位置是使用Durandal。
据我所知,加载数据的一般建议是在ViewModel的activate
方法中,这是我通常要做的-类似:
viewModel.activate = function () {
var loadPromise = myService.loadData();
return $.when(loadPromise).then(function (loadedData) {
viewModel.data(data);
});
};
我知道,如果我不在此处退还 promise ,那么绑定(bind)通常会出现问题-如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被更新以反射(reflect)正在加载的页面,但是页面内容仍显示前一页(这就是我所说的“卡住”)。
理想情况下,最好将URL更改为新页面,并且页面内容也应显示新页面(即使尚未返回该页面的数据)。然后,随着每个加载操作的返回,当将数据绑定(bind)到 View 模型中时,页面的相关部分应该被更新。
在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
的方法不是一个很好的解决方案。我也不确定是否可能出现比赛状况,因为我允许进行激活。还有其他建议吗?
最佳答案
您不必返回 promise ,但在这种情况下,必须在剔除绑定(bind)中处理此 promise ,这样就不会绑定(bind)到未定义的元素。您可以尝试取消激活中的“返回”,但添加一个属性,指示是否仍在加载模型。像这样的东西:
viewModel.isLoading = ko.observable(false);
viewModel.activate = function () {
isLoading(true);
var loadPromise = myService.loadData();
$.when(loadPromise).then(function (loadedData) {
viewModel.data(data);
isLoading(false);
});
};
然后,在您的 View 中,可以有一个部分,该部分在 View 仍在加载时显示,而在加载完成时显示。像这样:
<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>