setTimeout() 和 setInterval() 可以用来实现延时 定时等功能, 但是 JavaScript 是单线程工作, 不能同时执行多个操作 , 只能按照队列先后顺序执行, 定时器仅仅是计划代码在未来执行什么时间执行, 但是这个时间是不能保证的(不能保证定时器延迟), 是不精确的.
# timer 工作原理
(https://johnresig.com/blog/how-javascript-timers-work/)
首先,在JavaScript的第一个块中,启动两个定时器:10ms setTimeout和10ms setInterval。由于定时器启动的位置和时间,它实际上在我们实际完成第一个代码块之前触发。但请注意,它不会立即执行(由于线程,它无法执行此操作)。相反,延迟功能排队,以便在下一个可用时刻执行。
此外,在第一个JavaScript块中,我们看到鼠标单击。与此异步事件关联的JavaScript回调(我们永远不知道用户何时可以执行操作,因此它被认为是异步的)无法立即执行,因此,与初始计时器一样,它排队等待稍后执行。
在JavaScript的初始块完成后,执行浏览器会立即询问:什么等待执行?在这种情况下,鼠标单击处理程序和计时器回调都在等待。然后浏览器选择一个(鼠标单击回调)并立即执行它。计时器将等到下一个可能的时间,以便执行。
请注意,当鼠标单击处理程序执行时,执行第一个间隔回调。与计时器一样,它的处理程序排队等待以后执行。但是,请注意,当再次触发间隔时(执行计时器处理程序时),此时将删除处理程序执行。如果要在执行大块代码时排队所有间隔回调,结果将是一堆间隔执行时,它们之间没有延迟,完成后。相反,浏览器倾向于等待,直到排队更多时,不再有间隔处理程序排队(对于所讨论的间隔)。
事实上,我们可以看到,当间隔本身正在执行时,第三个间隔回调会触发。这向我们展示了一个重要的事实:Intervals不关心当前正在执行的内容,它们将不加选择地排队,即使这意味着将牺牲回调之间的时间。
最后,在第二个间隔回调完成执行后,我们可以看到JavaScript引擎没有任何内容可以执行。这意味着浏览器现在等待发生新的异步事件。当间隔再次发射时,我们得到50ms的标记。然而,这次没有任何东西阻止它的执行,所以它会立即触发。
# setTimeout() 和 setInterval()
|
|
|
|
这两段代码乍一看似乎在功能上等同,但它们不是。值得注意的是,setTimeout代码在前一次回调执行后总是至少有10ms的延迟(它可能最终会更多,但永远不会更少, setTimeout 链式调用是为了防止定时器 setInterval() 因为延迟而可能出现的两个缺点: 1) 某些间隔会被跳过 2) 多个定时器的代码执行之间的间隔可能会比预期小 ),而setInterval无论最后一次回调何时被执行,它都会尝试每10ms执行一次回调。
# 如何得到相对精确的倒计时(秒杀活动, 不同的人得到的时间不一致问题)
不使用客户端的时间, 使用服务器的时间, 但是使用服务器时间也有传输时间消耗和渲染时间消耗, 所以不能做到绝对精确, 但是可以通过优化来达到相对的精确, 控制误差.
当前服务器时间 = 服务器系统返回时间 + 网络传输时间 + 前端渲染时间
通过计算获得服务器时间后到前端渲染完成的时间差, 来动态调整定时器的间隔来缩小误差.
|
|