根据documentation的说法,setTimeout的实际延迟可能比所要求的更长。您能否在文档或问答中说明setTimeout的实际延迟是否会比所要求的更短?
问题是我遇到了一个很少发生的问题,可以用这样的现象来解释。平台: Chrome版本67,NodeJS版本9.8.0。另外,我真的很好奇,这句话对Firefox和其他浏览器来说是真的吗?
发布于 2018-06-18 22:42:49
您可以通过获取两个微秒的增量来测试超时或间隔准确性。在我的测试中,计时器是正负几毫秒。运行下面的程序,在您自己的环境中查看结果。
在理想情况下,输出总是显示1000
。输出中的差异意味着我们的世界是不完美的
var last = Date.now()
var interval = setInterval(function() {
var now = Date.now()
var delta = now - last
console.log(delta)
last = now
}, 1000)
setTimeout(clearInterval, 10000, interval)
// 1000
// 1003
// 998
// 1002
// 999
// 1007
// 1001
// ...
要显著影响结果,请按Run,切换到另一个选项卡,然后在几秒钟后返回到此选项卡。您将看到分散的选项卡具有极高的方差。
// 1004 <-- start experiment
// 997
// 1000 <-- switch to another tab
// 1533 <-- variance spikes immediately
// 866
// 1033
// 568 <-- switch back to this tab
// 1001 <-- variance restabilizes
// 1000
// 999
我不知道影响JavaScript中超时和时间间隔准确性的所有因素,但我也不认为这是一件需要了解的重要事情。最终,我们不需要精度,因为我们可以使用上面的增量技术来计算精确的持续时间。
在React中的一个实用示例
下面我们创建一个简单的Timer
组件,它简单地使用setInterval
每秒刷新一次计时器的显示。
class Timer extends React.Component {
constructor (props) {
super (props)
this.state = { seconds: 0, timeout: null }
}
componentDidMount () {
this.setState ({
timeout: setInterval (this.tick.bind(this), 1000)
})
}
componentWillUnmount () {
clearTimeout (this.timeout)
}
tick () {
this.setState ({ seconds: this.state.seconds + 1 })
}
render () {
return <div>Naive timer: {this.state.seconds}</div>
}
}
ReactDOM.render
( <Timer />
, document.getElementById ('timer')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="timer"></div>
但是由于JavaScript计时器的不可靠特性,我们知道我们的计时器组件最终会显示不正确的值。
当我们实现下面的PreciseTimer
时,我们可以使用增量技术来确保组件始终显示正确的持续时间
class PreciseTimer extends React.Component {
constructor (props) {
super (props)
this.state = { start: Date.now (), seconds: 0, timeout: null }
}
componentDidMount () {
this.setState ({
timeout: setInterval (this.tick.bind(this), 1000)
})
}
componentWillUnmount () {
clearTimeout (this.timeout)
}
tick () {
const delta = Date.now () - this.state.start
this.setState ({ seconds: delta / 1000 })
}
render () {
return <div>Precise timer: {this.state.seconds}</div>
}
}
ReactDOM.render
( <PreciseTimer />
, document.getElementById ('timer')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="timer"></div>
要查看这两个计时器行为的实际差异,请启动这两个计时器,切换到新选项卡10-15秒,然后切换回此选项卡。朴素的Timer
将受到JavaScript计时器变化的影响,而PreciseTimer
将始终显示正确的持续时间。
发布于 2018-06-18 22:43:12
实际上,在指定的延迟之后,setTimeout只会将回调推到事件循环的顶部,但是因为Javascript是单进程的,如果有什么东西阻塞了事件循环,回调就会被延迟。但它不能更短,或者是使用的代码/ javascript引擎中的错误。
发布于 2018-06-18 22:44:26
Javascript的单一执行线程意味着,有时您排队等待将来在点x执行的东西,实际上可能会在时间x+上执行,因为可能没有可用的执行时间范围。然而,在所需的时间之前,程序永远不能执行,只能在给定的时间内或之后执行。
例如,一个setTimeout(myFunc, 100 )可以在100ms后执行,或者更长一点。您可以在本文中找到更多关于javascrip计时器的一般信息:https://johnresig.com/blog/how-javascript-timers-work/
https://stackoverflow.com/questions/50911839
复制相似问题