为什么在事件回调之前执行间隔函数

Why is an interval function executed before an event callback?

本文关键字:执行 函数 事件 回调 为什么      更新时间:2023-09-26

我意识到javascript on scroll事件有些奇怪。

直到现在,我一直坚信,只要滚动位置发生变化,它就会被直接触发
因为javascript是阻塞的,回调总是第一个执行的,也是第一个"看到"这个新值的函数——或者我是这么认为的。

这里我有一个简单的设置,全局值在滚动时更新到当前滚动位置。然后有一段时间来比较两者
现在,如果你滚动得很快,有时确实会发生这种情况,缓存的值与实际返回的滚动位置不同。

// cache scroll pos
var scrollPos = 0;
// update on scroll
window.onscroll = function () {
    scrollPos = scrollTop();
};
// compare on interval
setInterval(function () {
    if (scrollPos != scrollTop()) {
        console.log("Out of sync!  cached:", scrollPos, "| actual:", scrollTop());
    }
}, 100);

小提琴:http://jsfiddle.net/71vdx4rv/2/
您可以尝试快速滚动或使用按钮。[在Chrome、Safari、FF、Opera上测试]

为什么在回调之前执行interval函数并知道"新"滚动位置
有人能给我解释一下吗?

直到现在,我一直坚信,只要滚动位置发生变化,它就会被直接触发。

不幸的是(显然)情况并非如此。而DOM 3确实状态为

当文档视图或元素滚动时,用户代理必须调度[scroll]事件。此事件类型是在滚动发生后分派的

这并不意味着"立即"。CSSOM草案澄清:

[要执行滚动,请重复运行以下步骤]:

  1. 执行从boxposition的[平滑或即时]滚动
  2. 对要运行task的任务进行排队,除非队列中有要运行task的任务

[其中task确实向相应目标发射scroll事件]

"任务队列"明确表示事件是异步调度的,因此在滚动事件触发任务之前执行等待任务(如计时器)时,滚动位置可能已经更改。

此外,当执行平滑滚动时,在对任务进行排队以激发scroll事件之前,允许浏览器在任意时间跨度内多次改变滚动位置。