【问题标题】:Why is an interval function executed before an event callback?为什么在事件回调之前执行间隔函数?
【发布时间】:2014-09-05 12:11:05
【问题描述】:

我意识到 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 上测试]

为什么在回调之前执行间隔函数并知道“新”滚动位置?
有人可以向我解释一下吗?

【问题讨论】:

  • onscroll 不会连续触发,因此计时器可以在更新之间执行......
  • 不,这不是原因。当然计时器可以在更新之间执行,但我认为在滚动事件回调之后它总是会有新的滚动位置值。请参阅已接受的答案以了解其原因。
  • 老兄,我的评论是 Bergi 所说的大致要点。 onscroll !== 与页面实际移动的 1 对 1 关系,这意味着它不是连续向上流动的更新。哎呀。

标签: javascript scroll setinterval event-loop onscroll


【解决方案1】:

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

不幸的是(显然)情况并非如此。而DOM 3 does state

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

这并不意味着“立即”。 CSSOM draft clarifies

[要执行滚动,请重复执行这些步骤]:

  1. box [平滑或即时] 滚动到position
  2. 将要运行的任务排入队列 @9​​87654326@,除非要运行的任务 task 在队列中。

[task 会在相应目标处触发 scroll 事件]

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

此外,在执行平滑滚动时,允许浏览器在任意时间跨度内多次更改滚动位置,然后将任务排队以触发 scroll 事件。

【讨论】:

    猜你喜欢
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多