in src/bindingHandlers/fastForeach.ts [119:169]
FastForEach.prototype.onArrayChange = function (changeSet, isInitial) {
const self = this;
const changeMap = {
added: [],
deleted: []
};
// knockout array change notification index handling:
// - sends the original array indexes for deletes
// - sends the new array indexes for adds
// - sorts them all by index in ascending order
// because of this, when checking for possible batch additions, any delete can be between to adds with neighboring indexes, so only additions should be checked
for (let i = 0, len = changeSet.length; i < len; i++) {
if (changeMap.added.length && changeSet[i].status == "added") {
let lastAdd = changeMap.added[changeMap.added.length - 1];
const lastIndex = lastAdd.isBatch ? lastAdd.index + lastAdd.values.length - 1 : lastAdd.index;
if (lastIndex + 1 == changeSet[i].index) {
if (!lastAdd.isBatch) {
// transform the last addition into a batch addition object
lastAdd = {
isBatch: true,
status: "added",
index: lastAdd.index,
values: [lastAdd.value]
};
changeMap.added.splice(changeMap.added.length - 1, 1, lastAdd);
}
lastAdd.values.push(changeSet[i].value);
continue;
}
}
changeMap[changeSet[i].status].push(changeSet[i]);
}
if (changeMap.deleted.length > 0) {
this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);
this.changeQueue.push({ status: "clearDeletedIndexes" });
}
this.changeQueue.push.apply(this.changeQueue, changeMap.added);
// Once a change is registered, the ticking count-down starts for the processQueue.
if (this.changeQueue.length > 0 && !this.rendering_queued) {
this.rendering_queued = true;
if (isInitial) {
self.processQueue();
} else {
FastForEach.animateFrame.call(window, function () { self.processQueue(); });
}
}
};