Faster Sliding after a few hours of setTimeout

141 views Asked by At

I am using the following code to slide a set of DIV's after 90 seconds. Initially the sliding works just fine, but post a few hours the sliding stats happening more randomly.

 function loadTemplateDisplayInterval()
 {
    var timeload=90000;//slide will change after 1.5 mints  
    var count = <s:property value="#request.templates.size()" />;
    var timeOut=setTimeout(function() {
    var prev=display_div;
    display_div++;

    if($("#container_" + prev).is(":visible"))
    {   

        $("#container_" + prev).hide(100).removeClass("fadeInLeftBig").addClass("fadeOutRightBig");
        $("#container_"+display_div).show(100).removeClass("fadeOutRightBig").addClass("fadeInLeftBig");

    }

    if(display_div>count)
    {   

        display_div=1;
        prev=count;

        $("#container_" + prev).hide(100).removeClass("fadeInLeftBig").addClass("fadeOutRightBig");
        $("#container_"+display_div).show(100).removeClass("fadeOutRightBig").addClass("fadeInLeftBig");

        setTimeout(function() {
            loadTemplateDisplayInterval();
        },timeload);

     }
     else
     {
        loadTemplateDisplayInterval();
     }

    clearTimeout(timeOut);
}, timeload);
}

The Div's are structures as,

    <div class="container-fluid animated" id="container_1"
            style="opacity: 0.01">
            <div class="row">
                row 1
            </div>
   </div>
   <div class="container-fluid animated" id="container_2"
            style="opacity: 0.01">
            <div class="row">
                row 1
            </div>
   </div>
   <div class="container-fluid animated" id="container_3"
            style="opacity: 0.01">
            <div class="row">
                row 1
            </div>
   </div>

I am unable to think, y this could be happing. The only part we noticed was when we didnt have a d3.js component, this problem didnt occur.

EDIT: Update with d3.js code

    var font_size = new Array();
    var all_topics = new Array();

    $('#' + divid).css('height', graph_h + "px").css("width", row_6 + "px");

    $.post('<s:url value="/advance/topicsWarroomElement" />', {
        setting_id : setting_id
    }, function(data) {

    var vals = eval('(' + data + ')');
            if (vals.length > 15) {

                //var temp = vals.length - 12;
                vals = vals.slice(0,12);
            }

            for ( var i = 0; i < vals.length; i++) {
                var x = vals[i];
                var temp_font = getFont(x.weight, i);
                all_topics.push({
                    "Text" : x.text,
                    "Size" : temp_font,
                });

                font_size.push(temp_font);
            }

// console.log(all_topics);
var fill = d3.scale.category20();

        d3.layout.cloud().size([ row_6, graph_h ]).words(
                all_topics.map(function(d) {
                    return {
                        text : d.Text,
                        size : d.Size
                    };
                    console.log(d.Text);
                }))

        .padding(function(d) {
            if (d.size <= 25 && vals.length <= 5) {

                return 10;
            } else {

                return 5;
            }
        }).rotate(function() {
            return 0;
        }).fontSize(function(d) {
            return d.size;
        }).on("end", draw).start();

        function draw(words) {
        console.log(words);
            var element = document.getElementById(divid);
            d3.select(element).append("svg").attr("width", row_6).attr(
                    "height", graph_h).append("g").attr(
                    "transform",
                    function(d) {
                        return "translate(" + [ row_6 / 2, graph_h / 2 ]
                                + ")";
                    }).selectAll("text").data(words).enter().append("text")
                    .style("font-size", function(d, i) {
                        return font_size[i] + "px";

                    }).style("font-family", " Helvetica,Arial,sans-serif")
                    .style("fill", function(d, i) {
                        return fill(i);
                    }).attr("text-anchor", "middle").attr(
                            "transform",
                            function(d) {
                                return "translate(" + [ d.x, d.y ]
                                        + ")rotate(" + d.rotate + ")";
                            }).text(function(d) {
                        return d.text;
                    });
        }

        if (draw !== true) {

            progressbar(divid);
        }

        setTimeout(function() {
            getTopics(setting_id, graph_type, divid, true);

        }, 2 * interval * 60 * 1000);

    });

    font_size = [];
    all_topics = [];

EDIT 2 After the suggestions made it's evident that setTimeout or setInterval go bonkers after a while. I have added a time time interval check and my new method looks as given below. But even with that I see the time itself is not correct and the difference comes wrong at many time, any way out of this.

function loadTemplateDisplayInterval()
{
    console.log('call load template display ');
    var timeload=30000;//slide will change after 1.5 mints  
    var count = <s:property value="#request.templates.size()" />;
    var lastTrigger = new Date().getTime();

    var timeOut=setInterval(function() 
    {
        console.log('difference -->'+ (new Date().getTime() - lastTrigger));
        if((new Date().getTime() - lastTrigger)>=timeload)
        {
            lastTrigger= new Date().getTime();
            console.log('Entering timeout '+display_div);
            var prev=display_div;
            display_div++;

            if($("#container_" + prev).is(":visible"))
            {   
                $("#container_" + prev).hide(100).removeClass("fadeInLeftBig").addClass("fadeOutRightBig");
                $("#container_"+display_div).show(100).removeClass("fadeOutRightBig").addClass("fadeInLeftBig");
            }

            if(display_div>count)
            {   
                display_div=1;
                prev=count;

                $("#container_" + prev).hide(100).removeClass("fadeInLeftBig").addClass("fadeOutRightBig");
                $("#container_"+display_div).show(100).removeClass("fadeOutRightBig").addClass("fadeInLeftBig");
                console.log('call load template display if block');
                //loadTemplateDisplayInterval();
            }

        }
    }, 10000);
}

TIME LOG FROM ABOVE CALL This time log display that even the date difference in two consecutive calls comes incorrect. How can this be correct.

difference -->30058
Entering timeout 2
difference -->30053
Entering timeout 1
difference -->30052
Entering timeout 2
difference -->30058
Entering timeout 1
difference -->9999
difference -->9978

Regards, Ayush

1

There are 1 answers

8
alesc On

setInterval is sadly not precise. I once created a clock by using setTimeout(1000) and the result was a catastrophe - large fluctuations in triggered times, even as high as +-30%.

So running a long term iterative setTimer, possibility in the background (browser minimized) will probably be even more off-time as browsers tend to give minimized tabs/windows lower execution priority.

What you should do is: decrease the interval by, say, ~10 times and every time you get triggered, check the actual elapsed time from your last action. When the time is within your desired tolerance, fire your code. It is really important to measure absolute elapsed time, as summing-up triggered timeouts is not precise and the error gets bigger with every iteration.

EDIT: To get the current time in milliseconds since epoch, use new Date().getTime(). You can save this value every time you fire your action and check the elapsed time in the in-between intervals. Just subtract the values and when the approach your interval time, fire your action again.

EDIT 2: Example of measuring time between intervals: http://jsbin.com/jerizemala/1/edit?html,js,console