Last Updated: February 25, 2016
·
8.1K
· mo_roodi

Neat little ko.observableArray trick

Knockout’s observable arrays are a great way of holding an array of data for tables, and lists and check boxes. But manipulating these array can potentially result in a lot of knockout subscriptions being fired, and can result in a load on the UI. Imagine the following simple code:

var array = ko.observableArray([]);
for(var i=0; i<100; i++) {
    array.push(i);
}

What will happen in this instance is that for each and every iteration the knockout bindings will get updated. This means that we will end up with 100 updates the bindings. Now imagine that as well as the UI binding you have a separate subscription to the knockout observable using array.subscribe(function(value) { });. This will mean that over each iteration 2 separate subscriptions are being called.

This may be alright, but it may also put undue strain on the app. Consider this alternative:

var array = ko.observableArray([]);
for (var i=0; i<100; i++) {
    array().push(i);
}

array.notifySubscribers(array());

What will happen now is that instead of firing 100 subscriptions, it will just notify the subscribers once. It should be noted that by doing this knockout will be unwrapping the observable 100 times instead, which it would have too do anyway, we’re just deferring the call to notify subscribers until after we’ve updated the array. Another alternative is:

var array = ko.observableArray([]);
var tempArray = ko.utils.unwrapObservable(array);
for (var i=0; i<100; i++) {
    tempArray.push(i);
}

array(tempArray);

This will basically have the same effect, but it does require an additional variable. While my examples aren’t very complicated, when there’s a lot of data in the arrays this really will start to make a difference. It will also mean that the UI will only be updated once all the data has been added to the array. Incidentally the same will work for pop/shift/unshift/splice/slice too.

Just as an aside knockout doesn’t always know when elements within the array have been updated (unless you use splice) so
array.notifySubscribers(array());
will allow you to notify the arrays subscribers of the updated values.

2 Responses
Add your response

You don't necessarily need to use unwrapObservable. It's used for places when you accept input that might be observable or not. In this case we know it's an observable(because later we are updating it's value, if it wasn't an observable, it would have thrown).

So you can do this:

var array = ko.observableArray([]);
var tempArray = array();
for (var i=0; i<100; i++) {
    tempArray.push(i);
}

array(tempArray);
over 1 year ago ·

There is a utility function ko.utils.arrayPushAll which does basically this.

ko.utils.arrayPushAll(array(), dataFromServer);
array.valueHasMutated();
over 1 year ago ·