简体   繁体   中英

Why is this while JavaScript loop infinite?

I hate doing this. This is THE small piece to end a large project and my mind is fried...

Here's the code. It checks to see if an element is overflowing and resizes the font. It is supposed to resize it until it doesn't overflow. The condition for the loop seems to be ignored and the browser freezes... I feel that I'm missing something crucial in how jQuery works here.

$.fn.fontBefitting = function() {
    var _elm = $(this)[0];
    var _hasScrollBar = false; 
    while ((_elm.clientHeight < _elm.scrollHeight) || (_elm.clientWidth < _elm.scrollWidth)) {
        var fontSize = $(this).css('fontSize');
        fontSize = parseInt(fontSize.substring(0,fontSize.length-2))*0.95;
        $(this).css('fontSize',fontSize+'px');          
    }

}

Thanks in advance.

Change:

 fontSize = parseInt(fontSize.substring(0,fontSize.length-2))*0.95;

to:

 fontSize = parseInt(fontSize.substring(0,fontSize.length-2))-1;

Here's a Working Demo . When the font size reached 10px, 10*.95 was 9.5 which the browser was rounding up to 10px. Thus infinite loop.

You need to step through your code in a debugger and actually check your condition values to make sure they are changing how you expect. My guess is _elm.clientHieght and _elm.clientWidth aren't actually changing.

var fontSize = $(this).css('fontSize');
fontSize = parseInt(fontSize, ...

The unit you get from font-size is not necessarily (a) pixels, nor (b) the same unit as you put in.

It's not specified what unit is used to return the length, but in many browsers it is currently points. Since points are smaller than pixels, the integer length will be longer, so you can quite easily keep on *0.95 ing it forever.

Even if it were pixels, the browser could round the size up to the nearest pixel, making 95%-size the same size as 100% when you read it back. Or you could hit the minimum-font-size setting and you wouldn't be able to reduce it any more.

So instead of reading the current font size back on each step, keep the pixel size you want in a variable and reduce that variable each time. Then if you reach a predetermined lower bound for the value of that variable, give up.

You are probably running into an endless loop because the font size doesn't actually change. Eg if the font size found is 10px you will update it to become 9.5px which is probably rounded back to 10px by the browser. In that case nothing changes and the function will keep running forever.

You've got an unrelated problem when you do

$('div').fontBefitting()

This will make the text in the first div fit it's box, then make the font size of all the other divs the same as the first. This does not sound like intended behaviour. You would hope that it would make each div resize its text and only its text to fit.

You need to change your code to this:

$.fn.fontBefitting = function() {
    /* $.fn.* runs on a jQuery object. Make sure to return it for chaining */
    return this.each(function() {
        var fontSize = parseInt($(this).css('fontSize'));
        while (this.clientHeight < this.scrollHeight ||
               this.clientWidth < this.scrollWidth) {
            fontSize--;
            $(this).css('fontSize', fontSize + 'px');          
        }
    });
}

You're checking to see if the clientHeight or clientWidth are LESS than the scrollHeight or scrollWidth , and if they are you are REDUCING the font size? It will never converge under those circumstances. You want to INCREASE the font size.

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