在durandal中长时间运行负载操作

时间:2013-07-30 06:02:11

标签: javascript single-page-application durandal

我正在尝试找出运行长时间运行加载操作的最佳位置是使用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并不是一个好的解决方案。我也不确定是否存在竞争条件,因为我允许激活继续进行。

还有其他建议吗?

3 个答案:

答案 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将在大约两个版本中发布   周。