我正在尝试找出运行长期加载操作的最佳位置是使用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>

09-25 18:06