Knockout JS - наблюдение за мутацией в любом свойстве массива без ko.mapping

В моем приложении я должен показать только 5 лучших пунктов длинного списка, которые имеют самый высокий рейтинг. Я реализовал это следующим образом:

Длинный список - это массив, который я превратил в наблюдаемый массив со всеми элементами как наблюдаемые с помощью ko.mapping, а верхние 5 элементов - это вычисляемый массив, который зависит от длинного списка. Всякий раз, когда что-либо в длинном списке изменяется, вычисляемый массив прибегает к длинному списку и получает первые 5 элементов.

Моя проблема в том, что длинный массив с ko.mapping занимает 60 МБ памяти, тогда как без ko.mapping он занимает всего 4 МБ. Есть ли способ достичь этого эффекта без ko.mapping длинного массива?

Вот скрипка, в которой я воссоздал сценарий с меньшим и более простым длинным массивом, но это просто для вас, чтобы понять, о чем я говорю.

Это длинный массив, для демонстрации я сделал его длиной 12 элементов:

 this.longArray = ko.mapping.fromJS([
    {name:"Annabelle"},
    {name:"Vertie"},
    {name:"Charles"},
    {name:"John"},
    {name:"AB"},
    {name:"AC"},
    {name:"AD"},
    {name:"AE"},
    {name:"AF"},
    {name:"AG"},
    {name:"AH"},
    {name:"AJ"}
]);

И это вычисляемый массив (показывает только 5 лучших):

this.sortedTopItems = ko.computed(function() {
    return self.longArray().sort(function(a, b) { 
        if(a.name() < b.name()) return -1;
            if(a.name() > b.name()) return 1;
            return 0;
    }).slice(0, 5);
}, this);

Кнопка "изменить одну" предназначена для имитации изменения длинного массива, а кнопка сброса - для сброса массива в исходное состояние.

1 ответ

Вы уверены, что можете, но самым простым способом было бы отфильтровать данные перед тем, как положить их в нокаут. Если вы когда-либо заботитесь только о первых 5. Давайте предположим, что ваш длинный массив называется data, Обратите внимание, что я не могу проверить это прямо сейчас, но это должно дать вам хорошую идею.

const sortedTopItems = ko.observableArray([]);

// Call with new data
const update = (data) => {
    data.sort((a,b) => a.name - b.name);
    sortedTopItems(data.slice(0, 5));
}

Это обрабатывает случай для простых данных, где они не наблюдаемы. Если вы хотите, чтобы фактические элементы данных (строки) были наблюдаемыми, я бы сделал следующее:

const length = 5;

// Create an empty array and initialize as the observable
const startData = new Array(length).map(a => ({}));
const sortedTopItems = ko.observableArray(startData);

// Call with new data
const update = (data) => {
    data.sort((a,b) => a.name - b.name);

    for(let i = 0; i < length; i++) {
        const item = sortedTopItems()[i];
        ko.mapping.fromJS(data[i], item); // Updates the viewModel from data
    }
}
Другие вопросы по тегам