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
}
}