Knockout JS - fetching data from server and rebinding - front-end performance problems

163 views
Skip to first unread message

Gustavs Felsbergs

unread,
Jun 9, 2017, 10:04:36 PM6/9/17
to KnockoutJS

I have a demo application in which I have an array where all elements are observables. In this app I have a function that simulates a call from a server - getting the same array that is bound to the list, but with one item changed. This is the way I have implemented it:

this.serverDataSimulation=function(){
   aArray[Math.floor((Math.random() * 10) + 0)].name=Math.floor((Math.random() 
* 2000) + 1000);
    ko.mapping.fromJS(aArray, this.allItems);
}

aArray is the simulation of data fetched from the server where an unknown random item has changed and I am binding it to the list with ko.mapping. The problem is that this way the whole list gets rerendered, instead of only updating the one item. I still want all the elements of the array to be observables after the rebinding as well as before rebinding. Is there any way to fix this - to make Knockout understand it only has to update one item?

Andrew Vickers

unread,
Jun 10, 2017, 1:51:40 AM6/10/17
to KnockoutJS
Are you using knockout-projections?

Gunnar Liljas

unread,
Jun 10, 2017, 4:08:15 AM6/10/17
to knock...@googlegroups.com
this.allItems()[Math.floor((Math.random() * 10) + 0)].name(Math.floor(Math.random() * 2000 + 1000));


--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Gustavs Felsbergs

unread,
Jun 10, 2017, 8:45:26 AM6/10/17
to KnockoutJS
Would it work since it's not an observable array, but an array of observables?

Andrew Vickers

unread,
Jun 10, 2017, 11:34:43 AM6/10/17
to KnockoutJS
No, probably not.  I tried doing the mapping manually, but the performance gains were negligible.

Is the true issue that the UI thread freezes while the slow mapping process takes place?

If so, my advice is to use one a WebWorker.

You can send a copy of the entire current array of observables and a copy of the new data to a worker, and let the worker handle the mapping and send back an updated array of observables.  Then you'll just need to update 
this.allItems(responseFromWorker);

This would require more overhead, but should keep the browser thread responsive.  You could also just make the updated mapping calls asynchronous in the main thread, but a worker is probably best.

If the issue is really the rendering of the template, maybe a pagination strategy is in order?  Users can only process so much info on a screen at once anyway.

Gunnar Liljas

unread,
Jun 10, 2017, 5:21:35 PM6/10/17
to knock...@googlegroups.com
The mapping process is hardly the culprit. Don't update more than necessary.

/G

--

Gustavs Felsbergs

unread,
Jun 10, 2017, 6:21:09 PM6/10/17
to KnockoutJS
The serverDataSimulation is supposed to be a simulation for receiving data from server. The aArray is the answer from the server were only one object of the array has changed. Since the whole array is returned from the server, there is no way to know which object has changed. That is why this line of code is not going to solve this issue.
this.allItems()[Math.floor((Math.random() * 10) + 0)].name(Math.floor(Math.random() * 2000 + 1000));

To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.

Andrew Vickers

unread,
Jun 11, 2017, 7:41:13 AM6/11/17
to KnockoutJS
@Gunnar: While I think you are generally right about updating more efficiently, even that rather trivial mapping example took between 250-550ms on my MacBook. 

@Gustavs: I'm going to make the assumptions that the server will always return items in the same order and that items will never be removed from, only possibly updated or added to, the array.  If so, you can use ko.utils.compareArrays.  Those returned as "added" are the ones you want.  Keep in mind that it won't automatically unwrap the observable values inside arrays for comparison.  Therefore, you might want to hold onto a copy of the original data from the server, provided the client will not be mutating it, and do your comparisons against that.  Then you can update at specific indexes or push, as appropriate.  That will accomplish what Gunnar recommends about updating only as necessary, which will most directly address excessive re-rendering issues.
Reply all
Reply to author
Forward
0 new messages