寻找改进我的 javascript (jquery) 代码的想法。递归函数

Posted

技术标签:

【中文标题】寻找改进我的 javascript (jquery) 代码的想法。递归函数【英文标题】:Looking for thoughts on improvement of my javascript (jquery) code. Recursive function 【发布时间】:2012-07-19 02:06:35 【问题描述】:

我编写的这段代码可以制作一些淡入淡出的视觉“图块”。 但目前我遇到了一点性能问题。

尽管大多数浏览器都可以正常运行代码(尤其是 firefox),但有些浏览器(例如 safari)会在一段时间后出现问题(一段时间 = 15 秒)。

我认为这是由于我的递归函数(名为 changeopacity 的函数会在延迟时永远调用自己)?是吗?

但无论如何,问题在于这段代码对于大多数浏览器来说确实很繁重。有没有,或者更多我怎样才能让这段代码表现得更好?有什么想法吗? (代码示例会很好)谢谢:-)

实际代码:

$(document).ready(function () 

    var aniduration = 2000;
    var tilesize = 40;

    createtable(tilesize);



    $(".tile").each(function (index, domEle) 
        var randomdelay = Math.floor(Math.random() * 3000);
        setTimeout(function () 
            changeopacity(aniduration, domEle);
        , randomdelay);
    );



    $("td").click(function () 
        clickanimation(this, 9);
    );

    $("td").mouseenter(function () 
        var element = $(this).find("div");
        $(element).clearQueue().stop();
        $(element).animate(opacity: "0.6", 800);
    );


    $("td").css("width", tilesize + "px").css("height", tilesize + "px");



);

function createtable(tilesize) 
    var winwidth = $(window).width();
    var winheight = $(window).height();
    var horztiles = winwidth / tilesize;
    var verttiles = winheight / tilesize;


for (var y = 0; y < verttiles; y++)

    var id = "y" + y;
    $("#tbl").append("<tr id='" + id + "'></tr>");

    for (var x = 0; x < horztiles; x++)
    
        $("#" + id).append("<td><div class='tile' style='opacity: 0; width: " + tilesize + "px; height: " + tilesize + "px;'></div></td>");
    
   


function changeopacity(duration, element)
    var randomnum = Math.floor(Math.random() * 13);
    var randomopacity = Math.floor(Math.random() * 7);
    var randomdelay = Math.floor(Math.random() * 1000);

    if ($(element).css("opacity") < 0.3)
    
        if (randomnum != 4)
        
            if ($(element).css("opacity") != 0)
            animation(element, 0, duration, randomdelay);
        
        else
        
            animation(element, randomopacity, duration, randomdelay);
        
    
    else
    
        animation(element, randomopacity, duration, randomdelay);
    

    setTimeout(function () 
        return changeopacity(duration, element);
    , duration + randomdelay);


function animation(element, randomopacity, duration, randomdelay)
    $(element).clearQueue().stop().delay(randomdelay).animate(opacity: "0." + randomopacity, duration);



function clickanimation(column, opacitylevel) 
        var element = $(column).find("div");
        $(element).clearQueue().stop();
        $(element).animate("background-color": "white", 200);
        $(element).animate(opacity: "0." + opacitylevel, 200);
        $(element).delay(200).animate(opacity: "0.0", 500);
        //$(element).delay(600).animate("background-color": "black", 500);

【问题讨论】:

codereview.stackexchange.com 老兄,这太棒了! - 对不起,我的头上什么都没有。我得回去看看,这效果真的很酷。 David 谢谢 - 可能需要帮助... Blazemonger 我无法删除此帖子或将其移至代码审查页面...?无论如何,如果我发布在错误的类别上,对不起...... :-( 老实说,我认为这是您的动画功能。 jQuery 天生就很慢。如果你能自己写,我敢打赌你能写得更快。 有趣的想法 ExceptionLimeCat 但在我看来,很难让我自己像 jquery animate 那样运行“好”。但无论如何有趣的想法...... :-) 更多想法将不胜感激...... 【参考方案1】:

第一个问题是您为页面上的每个单元格创建一个setTimeout。唯一能够处理该问题的浏览器是 Internet Explorer,然后由于许多 CSS 更改导致重绘缓慢而失败。

我强烈建议您编写自己的事件调度程序。像这样的东西,我在大学项目中使用过:

var timer = 
    length: 0,
    stack: ,
    timer: null,
    id: 0,
    add: function(f,d) 
        timer.id++;
        timer.stack[timer.id] = f: f, d: d, r: 0;
        timer.length++;
        if( timer.timer == null) timer.timer = setInterval(timer.run,50);
        return timer.id;
    ,
    addInterval: function(f,d) 
        timer.id++;
        timer.stack[timer.id] = f: f, d: d, r: d;
        timer.length++;
        if( timer.timer == null) timer.timer = setInterval(timer.run,50);
        return timer.id;
    ,
    remove: function(id) 
        if( id && timer.stack[id]) 
            delete timer.stack[id];
            timer.length--;
            if( timer.length == 0) 
                clearInterval(timer.timer);
                timer.timer = null;
            
        
    ,
    run: function() 
        var x;
        for( x in timer.stack) 
            if( !timer.stack.hasOwnProperty(x)) continue;
            timer.stack[x].d -= 50;
            if( timer.stack[x].d <= 0) 
                timer.stack[x].f();
                if( timer.stack[x]) 
                    if( timer.stack[x].r == 0)
                        timer.remove(x);
                    else
                        timer.stack[x].d = timer.stack[x].r;
                
            
        
    
;

然后,不使用setTimeout,而是使用相同的参数调用timer.add。同样,您可以调用timer.addInterval,而不是setInterval

这将允许您拥有任意数量的计时器,并且它们都将运行在一个 setInterval 上,从而减少浏览器的问题。

【讨论】:

你不认为巨大的负载来自所有那些独立的 delay() 和 animate() 调用吗? 感谢您的回复 Kolink...我已经测试了代码,它似乎提高了性能 :-) 甚至 Safari 浏览器似乎运行得更好...没有像以前那样滞后运行了一段时间......太棒了......这取得了很大的进步......可能是使用这个代码吗?还是我必须自己做一个?再次感谢大佬!!! :-) 注意:即使把我的 var tilesize = 5;只确认您的代码有很大的改进......它的原因是滞后的,但现在浏览器至少可以处理它,而以前浏览器几乎不可能:-) 您能告诉我们改进后的代码吗?我很难想象如何集成这个计时器,因为您在原始代码中没有使用任何 intervals Bergi - 它实际上非常简单。只需添加计时器代码并将 setTimeout 替换为 timer.add :-) 我并没有真正使用他的 timer.addInterval【参考方案2】:

不错的动画 :-) 但是,我发现了一些错误和可能的改进:

您的表格不会在窗口大小调整时重建。不确定是错误还是功能:-) 使用delegated events。你有很多元素,每个事件处理程序都是昂贵的。遗憾的是,这不适用于非冒泡的 mouseenter 事件。 如果您不对 with 和 height 使用内联样式,那就太好了 - 这些不会改变。对于 div 来说,无论如何它们都是多余的。

我看不出所有这些元素都有 id 的原因。 html-string构建可能更简洁。

缓存元素!!!您在几乎每个变量上都使用jQuery 构造函数,构建一个新实例。只需重复使用它们!

您的changeopacity 函数看起来有点奇怪。如果不透明度低于 0.3,是否有 13 分之一的机会将动画设为零?这可能表达得更严格。您也可以将不透明度缓存到一个变量中,而不是每次都从 dom 中读取它。

没有理由将duration 和其他常量作为参数传递,它们永远不会改变并且可以在全局范围内使用。

您应该使用complete callback of the animate method,而不是使用超时。超时永远不会准确,它们甚至可能会干扰这里导致(小)问题。

var duration = 2000,
    tilesize = 40,
    clickopacity = 0.9;

$(document).ready(function () 

    filltable($("#tbl"), tilesize)
      .on("click", "td", clickanimation);

    $(".tile").each(function() 
        changeopacity($(this));
    );

    $("#tbl div").mouseenter(function () 
        $(this).clearQueue()
               .stop()
               .animate(opacity: "0.6", 800);
    );
);

function filltable(tbl, tilesize) 
    var win = $(window).width();
    var horztiles = win.width() / tilesize;
    var verttiles = win.height() / tilesize;

    for (var y = 0; y < verttiles; y++) 
        var tr = "<tr>";
        for (var x = 0; x < horztiles; x++)
            tr += "<td style='width:"+tilesize+"px;height:"+tilesize+"px;'><div class='tile' style='opacity:0;'></div></td>");
        tbl.append(tr+"</tr>");
    
    return tbl;


function changeopacity(element) 
    var random = Math.floor(Math.random() * 13);
    var opacity = Math.floor(Math.random() * 7);
    var delay = Math.floor(Math.random() * 1000);

    if (element.css("opacity") < 0.3 && random != 4)
        opacity = 0;

    element.clearQueue().stop().delay(delay).animate(
        opacity: "0." + opacity
    , duration, function() 
        changeopacity(element);
    );


function clickanimation() 
    $(this.firstChild)
      .clearQueue()
      .stop()
      .animate("background-color": "white", 200)
      .animate(opacity: "0." + clickopacity, 200)
      .delay(200).animate(opacity: "0.0", 500);
    //.delay(600)
    //.animate("background-color": "black", 500);

【讨论】:

这也很好......似乎使用 animate 方法的完整回调有所改进。尽管我不确定它是否比 Kolinks 的建议更快。但是你写它的有趣方式......以及许多小的改进......非常感谢你:-) 我喜欢委派的活动......我肯定会阅读更多内容...... :-) Weee ...无论如何明天会更多地研究您的代码并根据您的许多建议优化我的代码,然后将 timer.add 与回调动画方法进行比较...晚安:-) 如果你喜欢它,你仍然可以投票 :-) 我不确定 jQuery 如何在内部处理动画帧,但我猜挂在该队列上也可以节省 CPU 负载。

以上是关于寻找改进我的 javascript (jquery) 代码的想法。递归函数的主要内容,如果未能解决你的问题,请参考以下文章

javascript中如何用jquery寻找所需要的标签?

寻找 js(可能是 jQuery)时区(仅限)控制 UI 小部件

jQuery:链接动画是一个问题,改进我的代码

如果无法使用 Javascript/jQuery 加载视频,则隐藏视频容器

用于甘特图的 JavaScript / jQuery 库

如何使用 javascript/jquery 设置用户输入的样式