繁体   English   中英

setInterval和setTimeout延迟问题

[英]setInterval and setTimeout delay issues

我一直在尝试通过react-native中的递归setTimeout管理计时器。

但是我面临的问题是,在某些设备中,计时器要花更多的时间(例如,在100-150秒左右的计时器中需要1-4秒)。

我已经删除了setInterval,因为它比递归setTimeout差。 有什么想法可以使这个计时器完美吗?

编辑:主要问题是我在2个或更多设备中运行了应用程序(处于发布模式)。 计时器可以完美启动,但是设备中的延迟似乎很小,随着时间的推移,延迟会越来越大。

应用中的api调用是并行完成的。

码:

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)
}

永远不能保证时间 ”,
但以150毫秒为间隔的4秒差异确实可以看得出来。

避免这种情况的一种方法是将时序划分为较小的动态间隔,自我校正其自身的延迟。

这是一个愚蠢的实现,它将下一个滴答声重新安排到下一秒,并在每次滴答声中纠正其延迟:

 // 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> 

这就是我发现Chrome的setInterval实现确实可以纠正自身的方式...

如果您有很小的时间间隔触发回调,则基于JavaScript的计时器不适合,但是如果您有较长的时间间隔触发回调,则可以使用。 尝试使用此方法, https://github.com/ocetnik/react-native-background-timer希望这会带来更好的结果,岁差仍然是可疑的,因为它是相对术语。

暂无
暂无

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

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