Synchronizing scrollbars, scrollTop and scroll event loops I've been playing around synchronizing two scrollbars on a web application using JavaScript and jQuery (1.11.3). So far what I've been doing is any time a scroll event happens on one div, I use scrollTop to adjust the position on the other div:

$left = $("#left")
$right = $("#right")

$left.scroll(function () {
    $right.scrollTop($left.scrollTop());
});

$right.scroll(function () {
    $left.scrollTop($right.scrollTop());
});


(jsFiddle)

The problem comes from scrollTop triggering a scroll event on the element it's called from, creating a loop and making it misbehave on some browsers. 

JavaScript events are queued, so toggling a flag before and after a call to scrollTop is not working (and could possibly backfire). So I came up with this solution:

$left = $( "#left" )
scrollLeft = []

$right = $( "#right" )
scrollRight = []

$left.scroll( function () {
    if ( !scrollRight.pop() ) {
        scrollLeft.push( true );
        $right.scrollTop( $left.scrollTop() );
    }
} );

$right.scroll( function () {
    if ( !scrollLeft.pop() ) {
        scrollRight.push( true );
        $left.scrollTop( $right.scrollTop() );
    }
} );


(jsFiddle)

This actually works, even though the scroll event is triggered on the other div the code is not executed and the loop is broken. I'm using a queue with push and pop in case some browser calls event handlers in some weird way; possibly using a single boolean variable could suffice to guard scrollTop.

My question is, is there a better way of doing this?
As you never want to handle a triggered event, I can suggest making it simpler using a single sentinel flag:

$left = $("#left")
$right = $("#right")

// Use a simple sentinel to say we are busy handling an event
var scrolling = false;
var timer;
$left.scroll(function () {
    //console.log("left "  + $left.scrollTop() + " : " + $.now());
    if (!scrolling) {
        //console.log("SCROLLING LEFT");
        clearTimeout(timer);
        timer = setTimeout(function () {
            scrolling = true;
            $right.scrollTop($left.scrollTop());
            scrolling = false;
        }, 10);
    }
});

$right.scroll(function () {
    //console.log("Right " + $right.scrollTop() + " : " + $.now());
    if (!scrolling) {
        clearTimeout(timer);
        timer = setTimeout(function () {
            //console.log("SCROLLING RIGHT");
            scrolling = true;
            $left.scrollTop($right.scrollTop());
            scrolling = false;
        }, 10);
    }
});


Update:

With FireFox, it triggers multiple scroll events, in sequence, for a single mouse wheel move. The trick is to wait until it settles using a timer. I found 10ms seems to work fine.

JSFiddle: http://jsfiddle.net/8xaw2896/8/