2

約 1100 レコードのかなり大きなデータ セットがあります。このデータセットは、監視可能な配列にマップされ、ビューにバインドされます。これらのレコードは頻繁に更新されるため、監視可能な配列は ko.mapping.fromJS ヘルパーを使用して毎回更新されます。

この特定のコマンドは、すべての行を処理するのに約 40 秒かかります。ユーザー インターフェイスは、その期間だけロックされます。

ここにコードがあります -

var transactionList = ko.mapping.fromJS([]);

//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();

//Mapping the data to the observable array, which takes around 40s
ko.mapping.fromJS(data,transactionList)

これに対する回避策はありますか? それとも、パフォーマンスを向上させるために Web ワーカーを選択する必要がありますか?

4

4 に答える 4

1

Knockout.viewmodelは、このような大きなオブジェクト配列のビューモデルを作成する際に大幅に高速化された、knockout.mapping に代わるものです。大幅なパフォーマンスの向上に気付くはずです。

http://coderenaissance.github.com/knockout.viewmodel/

于 2012-12-26T22:28:18.997 に答える
0

次のような回避策も考えました。これにより、使用するコードの量が少なくなります-

var transactionList = ko.mapping.fromJS([]);

//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();

//Mapping the data to the observable array, which takes around 40s
// Instead of - ko.mapping.fromJS(data,transactionList)
var i = 0;

//clear the list completely first
transactionList.destroyAll();

//Set an interval of 0 and keep pushing the content to the list one by one.
var interval = setInterval(function () {if (i == data.length - 1 ) {
                                        clearInterval(interval);}

                                    transactionList.push(ko.mapping.fromJS(data[i++]));
                                }, 0);
于 2012-09-07T09:56:29.740 に答える
0

マッピングプラグインにも同じ問題がありました。Knockout チームは、マッピング プラグインは大規模な配列で動作することを意図していないと述べています。このようなビッグ データをページにロードする必要がある場合は、システムの設計が不適切である可能性があります。

これを修正する最善の方法は、ページの読み込み時にすべてのデータを読み込むのではなく、サーバーのページネーションを使用することです。アプリケーションのデザインを変更したくない場合は、いくつかの回避策が役立つ可能性があります。

  1. アレイを手動でマップします。

    var data = storage.transactions();
    var mappedData = ko.utils.arrayMap(data , function(item){
        return ko.mapping.fromJS(item);
    });
    
    var transactionList = ko.observableArray(mappedData);
    
  2. 配列を非同期的にマップします。別のスレッドで配列を部分的に処理し、進行状況をユーザーに報告する関数を作成しました。

    function processArrayAsync(array, itemFunc, afterStepFunc, finishFunc) {
        var itemsPerStep = 20;
    
        var processor = new function () {
            var self = this;
            self.array = array;
            self.processedCount = 0;
            self.itemFunc = itemFunc;
            self.afterStepFunc = afterStepFunc;
            self.finishFunc = finishFunc;
            self.step = function () {
                var tillCount = Math.min(self.processedCount + itemsPerStep, self.array.length);
                for (; self.processedCount < tillCount; self.processedCount++) {
                    self.itemFunc(self.array[self.processedCount], self.processedCount);
                }
    
                self.afterStepFunc(self.processedCount);
                if (self.processedCount < self.array.length - 1)
                    setTimeout(self.step, 1);
                else
                    self.finishFunc();
            };
        };
    
        processor.step();
    };
    

あなたのコード:

var data = storage.transactions();
var transactionList = ko.observableArray([]);

processArrayAsync(data,
    function (item) { // Step function
        var transaction = ko.mapping.fromJS(item);
        transactionList().push(transaction);
    },
    function (processedCount) { 
        var percent = Math.ceil(processedCount * 100 / data.length);
        // Show progress to the user.
        ShowMessage(percent);
    },
    function () { // Final function
        // This function will fire when all data are mapped. Do some work (i.e. Apply bindings).
    });

また、別のマッピング ライブラリを試すこともできます: knockout.wrap。マッピング プラグインよりも高速である必要があります。

私は2番目のオプションを選択しました。

于 2012-09-07T09:14:40.883 に答える
0

マッピングは魔法ではありません。ほとんどの場合、この単純な再帰関数で十分です。

function MyMapJS(a_what, a_path)
{
    a_path = a_path || [];

    if (a_what != null && a_what.constructor == Object)
    {
        var result = {};
        for (var key in a_what)
           result[key] = MyMapJS(a_what[key], a_path.concat(key));
        return result;
    }

    if (a_what != null && a_what.constructor == Array)
    {
        var result = ko.observableArray();
        for (var index in a_what)
           result.push(MyMapJS(a_what[index], a_path.concat(index)));
        return result;
    }

    // Write your condition here:
    switch (a_path[a_path.length-1])
    {
        case 'mapThisProperty':
        case 'andAlsoThisOne':
            result = ko.observable(a_what);
            break;
        default:
            result = a_what;
            break;
    }
    return result;
}

上記のコードは、オブジェクト階層の任意のレベルでmapThisPropertyおよびandAlsoThisOneプロパティからオブザーバブルを作成します。他のプロパティは一定のままです。値が存在するレベル (深さ) にa_path.lengthを使用するか、 a_pathのより多くの要素を使用して、より複雑な条件を表現できます。例えば:

if (a_path.length >= 2 
  && a_path[a_path.length-1] == 'mapThisProperty' 
  && a_path[a_path.length-2] == 'insideThisProperty')
    result = ko.observable(a_what);

条件でtypeOf a_whatを使用して、たとえばすべての文字列を監視可能にすることができます。一部のプロパティを無視して、特定のレベルで新しいプロパティを挿入できます。または、a_pathを省略することもできます。等。

利点は次のとおりです。

  • カスタマイズ可能 ( knockout.mappingよりも簡単)。
  • 必要に応じて、コピーして貼り付け、さまざまなオブジェクトの個々のマッピングを書き込むのに十分な短さ。
  • 小さいコードのknockout.mapping-latest.jsはページに含まれません。
  • 絶対に必要なことだけを行うので、より高速になるはずです。
于 2015-01-15T10:40:58.790 に答える