jcubic February 2016

How to limit or throttle the number of function calls (in order to increase performance) in this function call?

I have a function that look like this:

function someFunction(text) {
    $('.class').each(function() {
        var $this = $(this);
        if ($this.text().match(text)) {
           $this.addClass('found');
        } else {
           $this.removeClass('found');
        }
    });
}

and that function is executed in keyup event,

$('input[type=text]').keyup(function() {
   someFunction($(this).val());
});

on IE if there are lot of .class elements it can be slow, I thought that I could speed things up if I stop executing the each call if the function have been executed again before each is finished. How can I do this?

Answers


Rory McCrossan February 2016

You could speed this up by adding a slight delay to the keyup handler so that the DOM is only affected after typing has ended instead of on each keystroke. You can also use the :contains selector to find the elements. Try this:

function someFunction(text) {
    $('.class').removeClass('found').filter(':contains("' + text + '")').addClass('found');
}

var timer;
$('input[type=text]').keyup(function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
        someFunction(this.value);
    }, 100);
});

Also, as mentioned by @A.Wolff you could cache the .class selector, but this would only work if no .class elements are dynamically added to the DOM while you're searching:

var $elements = $('.class');
function someFunction(text) {
    $elements.removeClass('found').filter(':contains("' + text + '")').addClass('found');
}

var timer;
$('input[type=text]').keyup(function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
        someFunction(this.value);
    }, 100);
});


Erkan Özkök February 2016

Try adding return false; end of your function

function someFunction(text) {
    $('.class').each(function() {
        var $this = $(this);
        if ($this.text().match(text)) {
           $this.addClass('found');
        } else {
           $this.removeClass('found');
        }

    });
    return false;
}


Björn Ali Göransson February 2016

As I misunderstood the question, here're two optimizations instead (both can be used together):

Cache the query result, only occasionally updating it by timer

Not really beautiful but may provide a robust solution given that the performance gain is critical.

window.lastValue = null;

window.cachedElements = null;

window.updateCachedElements = function(){ cachedElements = $('.class'); };

function someFunction() {
    cachedElements.each(function() {
        var $this = $(this);
        if ($this.text().match(lastValue)) {
           $this.addClass('found');
        } else {
           $this.removeClass('found');
        }
    });
}

$('input[type=text]').keyup(function() {
    if(cachedElements === null) {
        updateCachedElements();
    }

    lastValue = $(this).val()

    someFunction();
});

setInterval(function(){ updateCachedElements(); someFunction(); }, 500);

Use debounce (a form of throttling) to minimize number of someFunction calls to 1/100ms or 10 per second

After (and outside) the someFunction definition, do:

someFunction = debounce(someFunction, 100);

Debounce implementation from underscore.js:

_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
        var last = (Date.now || new Date().getTime()) - timestamp;

        if (last < wait && last >= 0) {
            timeout = setTimeout(later, wait - last);
        } else {
            timeout = null;
            if (!immediate) {
                result = func.apply(context, args);
                if (!timeout) context = args = null;
            }
        }
    };

    return function() {
        context = this;
        args = arguments;
        timestamp = _.now();
        var callNow = imme 

Post Status

Asked in February 2016
Viewed 1,980 times
Voted 14
Answered 3 times

Search




Leave an answer