jQuery脚本效率

时间:2013-04-06 11:19:27

标签: javascript jquery performance

我在数百个div上使用下面名为textfill的jQuery函数。基本上它调整内部文本的大小以适应封闭的div,使文本的字体大小最大,因此较长的文本比较短的文本小,但是它们的最大字体大小可以不受div的溢出。

; (function($) {
    /**
    * Resizes an inner element's font so that the inner element completely fills the outer element.
    * @version 0.1
    * @param {Object} Options which are maxFontPixels (default=40), innerTag (default='span')
    * @return All outer elements processed
    * @example <div class='mybigdiv filltext'><span>My Text To Resize</span></div>
    */
    $.fn.textfill = function(options) {
        var defaults = {
            maxFontPixels: 40,
            innerTag: 'span'
        };
        var Opts = jQuery.extend(defaults, options);
        return this.each(function() {
            var fontSize = Opts.maxFontPixels;
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var maxHeight = $(this).height();
            var maxWidth = $(this).width();
            var textHeight;
            var textWidth;
            do {
                ourText.css('font-size', fontSize);

                textHeight = ourText.height();
                textWidth = ourText.width();
                fontSize = fontSize - 1;
            } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
            var pos = (maxHeight-textHeight)/2;
            ourText.css('top', pos +'px');
        });
    };
})(jQuery);

因为我在数百个div上运行此脚本,如下所示:

<div class="textDiv"><span>text appears here</span></div>

同时使用:

$('.textDiv').each(function() { $(this).textfill({ maxFontPixels: 28 })});  

需要40到70秒,具体取决于div的数量。我迫切需要调整代码,以便它运行得更快。我已经尝试了最后两个小时,但似乎无法让它跑得更快。有人可以帮忙吗?

修改

从评论中获取一些输入并将代码更改为:

var items = document.getElementsByClassName("textDiv");
for (var i = items.length; i--;) {
    $(items[i]).textfill({ maxFontPixels: 28 });
}

似乎有点快,但仍然很慢。

2 个答案:

答案 0 :(得分:1)

  

$('.textDiv').each(function() { $(this).textfill({ maxFontPixels: 28 })});

您使用的功能错误。每个(适当的)插件都可以在jQuery集合上运行,并且内置each,因此您无需将其置于调用之外。只是做

$('.textDiv').textfill({ maxFontPixels: 28 });

但我认为这不是你的实际问题;循环非常快,即使是100件物品也不会花费几秒钟。问题是

            ourText.css('font-size', fontSize);
            textHeight = ourText.height();
            textWidth = ourText.width();

在循环内部(实际上在两个嵌套循环中),因为它需要浏览器完全重排。您需要最小化对此部分的调用,例如使用某种二进制搜索(bisection)和/或应用近似字体大小的interpolation指标(字符数除以例如?)以获得良好的起始价值。

除此之外,可能还有其他一些小的优化:

  • 缓存$(this)
  • $(Opts.innerTag + ':visible:first', this);看起来像一个非常复杂的选择器。这真的是必要的,你期待隐藏的元素吗?将此类额外内容移至选项,默认情况下使用$(this).children().first()
  • 我不确定您的CSS,但是如何设置div的维度(您检索为maxHeight / maxWidth)?为了在更改内部字体大小时降低回流成本,额外的overflow:hidden可以提供帮助。

答案 1 :(得分:0)

显然瓶颈是最里面的循环(下一个是最内层的父亲,依此类推)。

为什么不使用“bisection”来查找字体大小?:

200个div:


Bisect解决方案(需要一些重构):

http://jsfiddle.net/nx2n2/8/

Time: ~700

当前解决方案

http://jsfiddle.net/pXL5z/3/

Time: ~1400

最重要的代码:

        var change = Math.ceil(fontSize / 2);
        while(true) {
            change = Math.ceil(change / 2);

            var prev = fontSize;
            do {
                fontSize = fontSize - change;
                ourText.css('font-size', fontSize);

                textHeight = ourText.height();
                textWidth = ourText.width();
            } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);

            change = Math.ceil(change / 2);            
            while (textHeight < maxHeight && textWidth < maxWidth) {
                fontSize = fontSize + change;
                ourText.css('font-size', fontSize);

                textHeight = ourText.height();
                textWidth = ourText.width();
            }

            var current = fontSize;
            if(prev == current) {
                break;
            }
        }

        // this is because you subtract after change in your original solution
        // only for 'compatibility' with original solution
        fontSize = fontSize - 1;