6

質問: ViewModel のすべてのクエリが実行されるまでノックアウト バインディングが適用されないようにコードを構成するにはどうすればよいですか?

更新: さらに調査と実験を行った結果、Deferred 関数に沿ったものを使用するとうまくいく可能性があると思います。いくつかの実装を試しましたが、すべてのクエリ結果が処理されるまでではなく、クエリが呼び出されるまで延期されます。私は明らかにここで何か間違ったことをしていますが、私のjavascript fooは弱いです。

使用されたテクノロジー: Entity Framework 5 w/ Oracle、.Net 4 Web API、Knockout 2.2、Breeze 0.71.3

状況: Breeze を使用して、POCO の Enumerable を取得する Web API メソッドを呼び出し、ノックアウト監視可能な配列にデータを入力し、その配列をビューの選択コントロールにバインドします。

問題: ViewModel バインディングをビューに適用する前に、簡単なクエリが完了しておらず、ノックアウト オブザーバブルが設定されていません。クエリ結果が返されると、ko オブザーバブルが入力されて選択コントロールが更新される間、UI は 5 ~ 7 秒間応答しません。ロギングに基づいて、これが問題のようです...

cshtml ファイル:

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

main.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に 1 つずつプッシュすることはめったにありません。DOM の更新が多すぎます。代わりに一時配列を作成し、 observableArrayをそれで更新します。これが、あなたが求めているパフォーマンスの問題に対する答えだと思います。

  2. すべての初期非同期ロード メソッドが完了したときに promise を返す初期化メソッドを設定します。

  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 を好みます
        関数 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 に答える