我正在尝试找出运行长时间运行加载操作的最佳位置是使用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,thirdLoad); // Don't return the promise - let activation proceed. }; viewmodel.viewAttached = function () { $.when(loadPromise).then(function (one,three) { viewmodel.one(one); viewmodel.two(two); viewmodel.three(three); }); };
它似乎工作,但我记得在某处依赖viewAttached阅读并不是一个好的解决方案.我也不确定是否存在竞争条件,因为我允许激活继续进行.
还有其他建议吗?
解决方法
你不必返回一个promise,但是在这种情况下你必须在你的敲除绑定中处理这个,所以你不会绑定到未定义的元素.您可以尝试在激活中删除“返回”,但添加一个属性,指示模型是否仍在加载.像这样的东西:
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>