Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combine throttling with subscription in knockoutjs?

Tags:

knockout.js

I have a function that performs some communication with a server to report the current screen geometry, etc.

    function sendScreenLayout() { 
        logElementLocations(exp.getPageCoordinates());
    };

I subscribe this function to some events in my code like this:

viewModel.onLayoutChange.subscribe(sendScreenLayout);
$('#right-splitter > #mainContent').resize(sendScreenLayout);
$(window).resize(sendScreenLayout);
...
setTimeout(sendScreenLayout, 1);

Some of these events may get sent too frequently to be usefully handled by the server, and I would like to throttle the requests to some reasonable rate.

The best I could come up with was something like this:

var triggerSend = ko.observable();

ko.computed(function() {
    triggerSend();
    logElementLocations(exp.getPageCoordinates());
}).extend({throttle: 200});

function sendScreenLayout() {
    triggerSend.valueHasMutated();
}

Is there a more succinct way of capturing this pattern, or is this the way to go?

like image 683
Gene Golovchinsky Avatar asked Aug 27 '12 17:08

Gene Golovchinsky


People also ask

What is deferred in knockout JS?

Deferred – Notifications happen asynchronously, immediately after the current task and generally before any UI redraws. Rate-limited – Notifications happen after the specified period of time (a minimum of 2-10 ms depending on the browser).

What is KnockoutJS used for?

KnockoutJS is basically a library written in JavaScript, based on MVVM pattern that helps developers build rich and responsive websites.

What is Ko observable?

An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted. The main advantage of KO is that it updates our UI automatically when the view model changes.


2 Answers

If you are using Underscore, you could use debounce like this:

var sendScreenLayout = _.debounce(function() { 
    logElementLocations(exp.getPageCoordinates());
}, 200);
...
$(window).resize(sendScreenLayout);
...

Otherwise, it's not really a pattern that Knockout supports directly. The solution you came up seems good enough, although here's an alternative:

var triggerSend = ko.computed({
    read: function() {},
    write: function(dummy) {
        logElementLocations(exp.getPageCoordinates());
    }
}).extend({throttle: 200});

function sendScreenLayout() {
    triggerSend(true);
}
like image 183
Michael Best Avatar answered Oct 20 '22 05:10

Michael Best


Assuming your viewModel.onLayoutChange is an observable, you can simply do:

ko.computed(function() {
    viewModel.onLayoutChange(); //implicitly subscribes this callback to changes
    logElementLocations(exp.getPageCoordinates());
}).extend({throttle: 200});
like image 30
Stop Putin Stop War Avatar answered Oct 20 '22 05:10

Stop Putin Stop War