简体   繁体   中英

Improving Efficiency in jQuery function

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

It's measuring pixel width of text on a page and truncating until text reaches 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;
    }
}

Any way to improve performance? How would I convert this to a bubble-sort function?

Thanks!

move the calls to $() outside of the loop, and store its result in a temporary variable. Running that function is going to be the slowest thing in your code, aside from the call to .html().

They work very very hard on making the selector engines in libraries fast, but it's still dog slow compared to normal javascript operations (like looking up a variable in the local scope) because it has to interact with the dom. Especially if you're using a class selector like that, jquery has to loop through basically every element in the document looking at each class attribute and running a regex on it. Every go round the loop! Get as much of that stuff out of your tight loops as you can. Webkit runs it fast because it has .getElementsByClassName while the other browsers don't. (yet).

可以使用二进制搜索代替在找到理想宽度之前一次删除一个字符。

I see that the problem is that you are constantly modifying the DOM in the loop, by setting the html of the 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 rendered elements is not a good practice from my point of view.

Maybe you could approach the problem from a different angle. Truncating to a fixed width is common.

Other possibility (hack?) if dont have choices, could be to use the overflow css property of the container element and put the … in other element next to the text. Though i recommend you to rethink the need of solving the problem the way you are intending.

Hugo

Other than the suggestion by Breton, another possibility to speed up your algorithm would be to use a binary search on the text length. Currently you are decrementing the length by one character at a time - this is O(N) in the length of the string. Instead, use a search 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();
    }

... }

One thing to note is that each time you add something to the DOM, or change the html in a node, the page has to redraw itself, which is an expensive operation. Moving any HTML updates outside of a loop might help speed things up quite a bit.

As other have mentioned, you could move the calls to $() to outside the loop. You can create a reference to the element, then just call the methods on it within the loop as 1800 INFORMATION mentioned.

If you use Firefox with the Firebug plugin, there's a great way of profiling the code to see what's taking the longest time. Just click profile under the first tab, do your action, then click profile again. It'll show a table with the time it took for each part of your code. Chances are you'll see a lot of things in the list that are in your js framework library; but you can isolate that as well with a little trial and error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM