6

我正在尝试找出运行长时间运行加载操作的最佳位置是使用 Durandal。

据我所知,加载数据的一般建议是在 ViewModel 的activate方法中,这是我通常所做的 - 类似于:

viewModel.activate = function () {
    var loadPromise = myService.loadData();

    return $.when(loadPromise).then(function (loadedData) {
        viewModel.data(data);
    });
};

我知道,如果我不在这里返回承诺,那么绑定通常会出现问题 - 正如这个问题和答案所表明的那样。

但是,在该方法中执行长时间运行的加载操作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不是一个好的解决方案。我也不确定是否存在竞争条件,因为我允许激活继续。

还有其他建议吗?

4

3 回答 3

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>
于 2013-07-30T10:02:19.870 回答
0

以供参考; 我在 Durandal Google Group 上发布了一个类似的问题(有效地询问以这种方式使用 activate 和 viewAttached 是否是一个好主意),并得到了 Rob Eisenberg 的回复:

那可能会奏效。问题是,如果更新了属性并且元素当前不在文档中,Knockout 将破坏元素上的数据绑定。这取决于异步代码的时间。由于组合在 1.x 中的工作方式,如果您没有从您的激活函数返回承诺,这将导致问题。它应该在 viewAttached 中工作得更好,但是根据您的组合的性质,视图可能会附加到其父级,但仍然不在文档中。这取决于构图的深度。所以,如果你在一个深度组合的模块中有这个,你也可能会遇到这个问题。不幸的是,由于淘汰行为,在 Durandal 1.x 中没有一个干净的方法。在杜兰达尔 2。x 我们已经重新设计了组合,因此这个问题不存在并且不再需要返回承诺(尽管你仍然可以这样做)。Durandal 2.0 将在大约两周后发布。

于 2013-08-01T05:17:51.903 回答
0

您使用的是哪个版本的 Durandal?在 Durandal 2.0.0pre 中,您将被允许不返回承诺,activate以便视图的组合(没有数据)可以立即发生。

您可能会考虑将等重构viewModel.one为一个返回构造函数的模块,以便每个一、二、三将负责检索自己的数据。这样你前两个电话就不必等待了loadThirdDataWhichTakesAges。在一个、两个、三个不严重相互依赖的情况下,这将是有意义的。

于 2013-07-30T07:08:14.523 回答