Scroll event skipped during event loop

Viewed 65

According to the HTML Standart in the event loop during updateing the rendering 2 things happen sequentially:

  1. For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
  1. For each fully active Document in docs, run the animation frame callbacks for that Document, passing in now as the timestamp.

Therefore I suppose that IF before the event loop run both

  • a scroll happens (via scrollTop or scrollLeft property of a scrollable element change or scrollTo execution)
  • a callback scheduled via requestAnimationFrame

THEN there should be at least one scroll event for each scrolled element in any event loop run,and callbacks execution always happens after scroll event listeners.

I wrote a function that checks this proposition and tried it in Chrome and FireFox:

function Test(iterations, stepTimeout) {

    let xOuter = document.createElement("div");
    xOuter.style.width = "100px";
    xOuter.style.height = "100px";
    xOuter.style.overflow = "scroll";
    //xOuter.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
    xOuter.style.zIndex = "10000";
    xOuter.style.position = "absolute";
    xOuter.style.top = "0";
    xOuter.style.left = "0";
    xOuter.style.scrollBehavior = "auto";
    let xInner = document.createElement("div");
    xInner.style.width = "200%";
    xInner.style.height = "200%";
    xOuter.appendChild(xInner);
    let xState = "What happens during each interation of Step:\n";
    let xStepIndex = 0,
        xScrollUpdateIndex = 0,
        xLastExecutedScrollUpdate = -1;
    xOuter.addEventListener("scroll", () => {
        xState += `scroll-${xScrollUpdateIndex} `;
        xLastExecutedScrollUpdate = xScrollUpdateIndex;
    });
    document.body.appendChild(xOuter);

    function Step() {
        if (xStepIndex > iterations) {
            xOuter && xOuter.parentNode && xOuter.parentNode.removeChild(xOuter);
            console.log(xState);
            return;
        }
        let xScrollProp = Math.random() > 0.5 ? "scrollLeft" : "scrollTop";
        let xOldScrollPos = xOuter[xScrollProp],
            xNewScrollPos;
        do {
            xNewScrollPos = Math.round(Math.random() * 200);
        } while (xOldScrollPos == xNewScrollPos);
        xState += `\n ${xStepIndex++} : [${xNewScrollPos}] `;
        xOuter[xScrollProp] = xNewScrollPos; // scroll event scheduled
        xScrollUpdateIndex++;
        let xCurrentScrollUpdateIndex = xScrollUpdateIndex;
        requestAnimationFrame(() => {
            if (xCurrentScrollUpdateIndex > xLastExecutedScrollUpdate)
                console.log("Scroll failed to fire before rAF");
            xState += `rAF-${xCurrentScrollUpdateIndex} `;
        });
        new Promise((resolve) => setTimeout(() => resolve(), stepTimeout)).then(Step);
    }

    Step();
}

Test(200, 10);

However it looks like in some event loop runs scroll event doesn't fire.
Is this an expected behavior?

0 Answers
Related