简体   繁体   English

setInterval和setTimeout延迟问题

[英]setInterval and setTimeout delay issues

I've been trying to manage a timer via recursive setTimeout in react-native. 我一直在尝试通过react-native中的递归setTimeout管理计时器。

But i'm facing the problem that in some devices the timer is taking some time more in process(like 1-4 seconds in around 100-150 seconds timer). 但是我面临的问题是,在某些设备中,计时器要花更多的时间(例如,在100-150秒左右的计时器中需要1-4秒)。

I've already removed setInterval as it was worse than recursive setTimeout. 我已经删除了setInterval,因为它比递归setTimeout差。 any ideas that how can i make this timer perfect? 有什么想法可以使这个计时器完美吗?

Edit: the main problem is that i ran application(In release mode) in 2 or more devices. 编辑:主要问题是我在2个或更多设备中运行了应用程序(处于发布模式)。 the timer starts perfectly but devices seem to have very small delay in them, which is quite increasing by time. 计时器可以完美启动,但是设备中的延迟似乎很小,随着时间的推移,延迟会越来越大。

The api calls in app are done parrallely. 应用中的api调用是并行完成的。

Code: 码:

AnotherTimerHandler = () => {
    this.time = setTimeout(() => {
        if (this.state.gameState == timesup) {
            console.log(timesup)
            this.setState({ timer: this.state.timer - 1 });
            if (this.state.timer <= 0) {
                if (this.state.questionIndex < numberOfQuestions - 1) {
                    this.setState({ gameState: splash, timer: splashTime, QAndA: {}, correctAnswer: '', questionIndex: this.state.questionIndex + 1, answered: false })
                } else {
                    // console.log('123')
                    clearInterval(this.time)
                    console.log(this.state.playerMode)

                    if (this.state.playerMode) {
                        const { username, firstName, lastName } = this.props.navigation.state.params.userData;
                        firebase.database().ref(`tblGame/${gameIdToLoad}/gameWinners`).push({ Email: firebase.auth().currentUser.email, Name: firstName + ' ' + lastName })
                            .then(() => this.props.navigation.navigate('Winner', { gameId: gameIdToLoad, prizeAmount: this.props.navigation.state.params.QuizData.prizeAmount }))
                            .catch(err => alert(err))
                    } else { this.props.navigation.navigate('Winner', { gameId: gameIdToLoad, prizeAmount: this.props.navigation.state.params.QuizData.prizeAmount }); }
                }
            }
        }
        else if (this.state.gameState == playing) {
            console.log('playing')
            if (this.state.timer == questionTimer) {
                // console.log('playing1', this.state.timer)
                // this.setState({ answerLoaded: false })
                // this.QAndAHandler(Question)
                this.refs.circularProgress.performLinearAnimation(0, (questionTimer - 1) * 1000)
            }
            this.setState({ timer: this.state.timer - 1 })
            // if (this.state.timer == -1) {
            if (this.state.timer <= 0) {
                this.setState({ gameState: timesup, timer: answerTimer }); this.QAndAHandler(Ans);
                // console.log('playing2', this.state.timer)
            }
        }
        else if (this.state.gameState == splash) {
            console.log(splash)
            console.log(this.state.timer)
            this.setState({ timer: this.state.timer - 1 })
            if (this.state.timer == splashTime - 1) {
                this.QAndAHandler(Question)
            } else if (this.state.timer <= 0) this.setState({ timer: questionTimer, gameState: playing, answerLoaded: false })
        }
        // Dont call again if scren is being changed 
    return this.state.gameState == timesup && this.state.timer<=0 && !(this.state.questionIndex < numberOfQuestions - 1) ? null : this.AnotherTimerHandler()    
    }, 1000)
}

" Timing is never guaranteed ", 永远不能保证时间 ”,
but 4 seconds difference on 150ms interval can indeed be seen as big. 但以150毫秒为间隔的4秒差异确实可以看得出来。

One way to circumvent this is splitting your timings in smaller dynamics intervals, self-correcting its own delay. 避免这种情况的一种方法是将时序划分为较小的动态间隔,自我校正其自身的延迟。

Here is a dumb implementation that will reschedule the next tick to the next second, correcting itself its delay at every tick: 这是一个愚蠢的实现,它将下一个滴答声重新安排到下一秒,并在每次滴答声中纠正其延迟:

 // Self-correcting setInterval // intended for long intervals // returns an object which "_id" property is the inner timeout id, so it can be canceled by clearInterval function selfCorrectingInterval(cb, ms) { var innerTimeout = ms < 1000 ? 100 : 1000, // fire every ?s begin = performance.now(), // what time is it? last = begin + ms, // when should all this end? next = Math.min(innerTimeout, ms), prev = begin, result = { _id: setTimeout(inner, next) }, passed = true; // a flag to avoid try-catch the callback return result; function inner() { if (!passed) return; passed = false; // set up the callback trap var shouldCall = false; var now = performance.now(), delay = (now - prev) - innerTimeout; prev += innerTimeout; // fixed increment if (last - now < 6) { shouldCall = true; begin = last; // start a new interval last += ms; } next = Math.min(innerTimeout - delay, last - now); result._id = setTimeout(inner, next); // call it at the end so we can cancel inside the callback if (shouldCall) { cb(); } passed = true; // didn't throw we can continue } } // snippet-only tests function test(ms) { function setTimeoutLoop(cb, ms) { function loop() { cb(); setTimeout(loop, ms); } setTimeout(loop, ms); } var now = performance.now(), built_in_prev = now, timeout_prev = now, sCI_prev = now, built_in_elem = document.querySelector('#test_' + ms + ' .delay.built_in'), timeout_elem = document.querySelector('#test_' + ms + ' .delay.timeout'), sCI_elem = document.querySelector('#test_' + ms + ' .delay.sCI'); setInterval(() =>  { var now = performance.now(), delay = (now - built_in_prev) - ms; built_in_prev += ms; built_in_elem.textContent = Math.round(delay); }, ms); setTimeoutLoop(() => { var now = performance.now(), delay = (now - timeout_prev) - ms; timeout_prev += ms; timeout_elem.textContent = Math.round(delay); }, ms); selfCorrectingInterval(() =>  { var now = performance.now(), delay = (now - sCI_prev) - ms; sCI_prev += ms; sCI_elem.textContent = Math.round(delay); }, ms); } test(1000); test(5000); test(60000); test(150000); 
 [id^='test'] { border: 1px solid; padding: 0 12px } 
 <div id="test_1000"> <p>built in setInterval delay for 1000ms interval: <span class="delay built_in">0</span>ms</p> <p>built in setTimeout loop delay for 1000ms interval: <span class="delay timeout">0</span>ms</p> <p>selfCorrectingInterval delay for 1000ms interval: <span class="delay sCI">0</span>ms</p> </div> <div id="test_5000"> <p>built in setInterval delay for 5000ms interval: <span class="delay built_in">0</span>ms</p> <p>built in setTimeout loop delay for 5000ms interval: <span class="delay timeout">0</span>ms</p> <p>selfCorrectingInterval delay for 5000ms interval: <span class="delay sCI">0</span>ms</p> </div> <div id="test_60000"> <p>built in setInterval delay for 1 minute interval: <span class="delay built_in">0</span>ms</p> <p>built in setTimeout loop delay for 1 minute interval: <span class="delay timeout">0</span>ms</p> <p>selfCorrectingInterval delay for 1 minute interval: <span class="delay sCI">0</span>ms</p> </div> <div id="test_150000"> <p>built in setInterval delay for 150s interval: <span class="delay built_in">0</span>ms</p> <p>built in setTimeout loop delay for 150s interval: <span class="delay timeout">0</span>ms</p> <p>selfCorrectingInterval delay for 150s interval: <span class="delay sCI">0</span>ms</p> </div> 

And that's how I discover Chrome's implementation of setInterval already does correct itself... 这就是我发现Chrome的setInterval实现确实可以纠正自身的方式...

If you have very small time interval to fire your callback then javascript based timer would not be suitable, but if you have longer time interval to fire your callback then that will work. 如果您有很小的时间间隔触发回调,则基于JavaScript的计时器不适合,但是如果您有较长的时间间隔触发回调,则可以使用。 Try using this, https://github.com/ocetnik/react-native-background-timer Hope this would give better result, precession will be still questionable as it is relative term. 尝试使用此方法, https://github.com/ocetnik/react-native-background-timer希望这会带来更好的结果,岁差仍然是可疑的,因为它是相对术语。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM