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

时间:2012-07-19 20:07:14

标签: javascript jquery function recursion jquery-animate

我制作了这个代码,使得一些视觉“瓦片”渐渐消失。 但目前我遇到了一些性能问题。

虽然大多数浏览器正在运行代码(特别是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);
}

2 个答案:

答案 0 :(得分:2)

首要问题是您要为网页上的每个单元格创建一个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。同样,您可以拨打setInterval而不是timer.addInterval

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

答案 1 :(得分:2)

好动画:-)然而,我发现了一些错误和可能的改进:

  • 您的表格未在窗口调整大小上重建。不确定是否有bug或功能: - )
  • 使用delegated events。你有很多元素,每个事件处理程序都很昂贵。遗憾的是,这对于非冒泡的mouseenter事件无效。
  • 如果你不使用with和height的内联样式会很好 - 那些不会改变。对于div来说,无论如何它们都是superflouos。
  • 我看不出所有这些元素都有id的原因。 html-string构建可能更简洁。

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

  • 您的changeopacity函数看起来有点奇怪。如果不透明度低于0.3,那么动画为零的概率为1/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);
}