6

问题: 如何构造我的代码,以便在执行 ViewModel 的所有查询之前不应用淘汰绑定?

更新: 经过一些进一步的研究和实验,我认为使用类似于 Deferred 函数的东西可能会起作用。我已经尝试了一些实现,但是它只推迟到调用查询,而不是直到处理完所有查询结果。我显然在这里做错了,但我的 javascript foo 很弱。

使用的技术: Entity Framework 5 w/Oracle、.Net 4 Web API、Knockout 2.2、Breeze 0.71.3

情况: Breeze 被用于调用 Web API 方法,该方法检索 POCO 的 Enumerable,填充可淘汰的可观察数组,并且该数组绑定到视图中的选择控件。

问题: 在将 ViewModel 绑定应用到 View 之前,微风查询尚未完成,并且剔除可观察对象尚未填充。返回查询结果时,UI 会在 5 - 7 秒内无响应,同时填充 ko observable 并因此更新选择控件。根据日志记录,这似乎是问题所在......

cshtml 文件:

<select data-bind="options: $root.brokers, value: 'id', optionsText: 'name'">
<script data-main="/BrokerCommission/Scripts/app/main" src="/BrokerCommission/Scripts/require.js"></script>

主.js:

requirejs.config(
    {
        // well-know paths to selected scripts
        paths: {
            'breeze': '../breeze.debug', // debug version of breeze
            'text': '../text'// html loader plugin; see http://requirejs.org/docs/api.html#text
        }
    }
);

define(['logger', 'text', 'breeze'], function(logger) {

require(['vm.muni'],
function()
{
    logger.info('applying bindings');
    ko.applyBindings(my.vm);
});

vm.muni 是我的 ViewModel javascript 文件。这是一个公开给执行查询的方法:

getAllBrokers = function () {
        dataservice.getBrokers()
            .then(processBrokerQueryResults)
            .fail(handleQueryErrors);
    },

    processBrokerQueryResults = function (data) {
        logger.info("Start loading Brokers " + Math.round(new Date().getTime() / 1000));
        my.vm.brokers([]);
        $.each(data.results, function (i, d) {
            brokers.push(new my.Broker()
                .id(d.id)
                .name(d.name)
            );
        });
        logger.info("End loading Brokers " + Math.round(new Date().getTime() / 1000));
    },

这是来自 dataservice.js 文件的微风查询:

function getBrokers() {
    var query = new entityModel.EntityQuery()
            .from("GetBrokers")
            //.orderBy("name");
    return manager.executeQuery(query);
};
4

1 回答 1

5

我有几个想法:

  1. 很少将一项一项推入observableArray。DOM 更新太多。而是创建一个临时数组并用它更新observableArray。我相信这是您所询问的性能问题的答案。

  2. 设置一个初始化方法,该方法在所有初始异步加载方法完成时返回一个承诺。

  3. 延迟ko.applyBindings直到初始化承诺成功解决。

  4. 考虑在等待初始化完成时显示启动画面 + 微调器。

  5. 初始化时尽量不要做太多。

我无法在此答案中向您展示如何做所有这些事情。我将在这里向您展示#1,并在#2 的文档中向您介绍“ Fetch on Launch ”。网络搜索 + 实验是您其余的朋友。

用数组 更新observableArray
processBrokerQueryResults = 函数(数据){
        ...
        var tempArray = []
        $.each(data.results, function (i, d) {
            tempArray.push(dtoToBroker(d));
        });
        经纪人(tempArray);
        ...

        // 我更喜欢命名 fns 而不是长 lambdas
        函数 dtoToBroker(dto) {
           返回新的 my.Broker()
                  .id(d.id)
                  .name(d.name);
        }

我喜欢使用 ECMAScript 5 Array.map语法,它在将函数应用于源数组的每个元素后返回一个数组。所以我会写:

processBrokerQueryResults = 函数(数据){
        ...
        经纪人(data.results.map(dtoToBroker));
        ...
}
于 2012-11-28T23:53:21.083 回答