Making jQuery function more efficient

The while statement in this function is too slow (prevents the page from loading for 4-5 seconds) in IE / firefox, but fast in safari ...

It measures the pixel width of the text on the page, and crops until the text reaches the ideal width:

function constrain(text, ideal_width){

    $('.temp_item').html(text);
    var item_width = $('span.temp_item').width();
    var ideal = parseInt(ideal_width);
    var smaller_text = text;
    var original = text.length;

    while (item_width > ideal) {
        smaller_text = smaller_text.substr(0, (smaller_text.length-1));
        $('.temp_item').html(smaller_text);
        item_width = $('span.temp_item').width();
    }

    var final_length = smaller_text.length;
    if (final_length != original) {
        return (smaller_text + '…');
    } else {
       return text;
    }
}

      

How can you improve performance? How would I convert this to a bubble sort function?

Thanks!

0


a source to share


5 answers


move calls to $ () outside the loop and store its result in a temporary variable. Running this function will be the slowest in your code other than calling .html ().



They are working very hard to make the selector engines in the libraries fast, but it is still slow compared to normal javascript operations (like finding a variable in the local scope) because it has to interact with the dom. Especially if you use a class selector like this, jquery has to loop through each element in the document, looking at each class attribute and running a regex on it. Everyone goes on a loop! Get as much of this stuff out of your hard cycles as you can. Webkit is fast because it has a .getElementsByClassName while other browsers don't. (While).

+5


a source


Instead of deleting one character at a time until you find the perfect width, you can use binary search .



+4


a source


I see the problem is that you are constantly changing the DOM in a loop by setting the html temp_item and then re-reading the width.

I don't know the context of your problem, but trying to adjust the layout by measuring the items displayed is not good practice from my point of view.

Perhaps you could approach the problem from a different angle. Truncation to a fixed width is common.

Another possibility (hack?), If you have no choice, might be to use the container element overflow css property and put the & hellip; in another element next to the text. Although I recommend that you rethink the need to solve the problem the way you plan.

Hugo

+2


a source


Besides Breton's suggestion, another way to speed up your algorithm would be to use a binary search on the length of the text. Currently you are decreasing the length one character at a time - that's O (N) in the length of the string. Use search instead, which will be O (log (N)).

Roughly speaking, something like this:

function constrain(text, ideal_width){

      

...

    var temp_item = $('.temp_item');
    var span_temp_item = $('span.temp_item');

    var text_len_lower = 0;
    var text_len_higher = smaller_text.length;

    while (true) {
          if (item_width > ideal)
          {
            // make smaller to the mean of "lower" and this
            text_len_higher = smaller_text.length;
            smaller_text = text.substr(0, 
                ((smaller_text.length + text_len_lower)/2));
          }
          else
          {
            if (smaller_text.length>=text_len_higher) break;

            // make larger to the mean of "higher" and this
            text_len_lower = smaller_text.length;
            smaller_text = text.substr(0, 
                ((smaller_text.length + text_len_higher)/2));
          }
          temp_item.html(smaller_text);
          item_width = span_temp_item.width();
    }

      

...}

+2


a source


It should be noted that every time you add something to the DOM or change the html in a node, the page has to be redrawn, which is an expensive operation. Moving any HTML updates outside of the loop can speed things up a bit.

As mentioned, you can move calls to $ () outside of the loop. You can create a reference to an element and then just call methods on it in a loop, as mentioned in the 1800 mentioned.

If you are using Firefox with the Firebug plugin, there is a great way to profile your code to see what takes the longest. Just click the profile under the first tab, take your action, and then click the profile again. It will show a table with the time taken for each piece of your code. You will most likely see a lot of things from the list that are in your js framework; but you can highlight this as well with a little trial and error.

+1


a source







All Articles