我正在使用useEffect反应钩子来设置倒计时变量的间隔。我注意到,当我浏览器中的选项卡未处于活动状态时,内部将停止工作。如果选项卡处于活动状态,则代码完全按预期工作。
有没有更好的方法可以做到这一点?下面是一个代码示例。
export default function CountdownTimer({ minutes_left, action }) {
const [timeLeft, setTimeLeft] = useState();
function updateTimer() {
const remaining = ...work out time left
setTimeLeft(remaining);
}
useEffect(() => {
const interval = setInterval(() => {
updateTimer();
if (timeLeft.asMilliseconds() <= 0) {
action();
clearInterval(interval);
}
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<p>{timeLeft}</p>
);
}
我已经在丹·阿布拉莫夫(Dan Abramov)关于这个问题的帖子中实施了解决方案。但是,当选项卡处于非活动状态时,Dan的解决方案也不会呈现。
请注意,这就是浏览器的工作方式:非活动选项卡的优先级降低,计时器受到严重限制。请记住,setTimeout
和setInterval
最明确的不是"在 X ms 通过后运行代码",它们是">在至少X ms 通过后运行代码",没有任何保证事情实际上不会发生太多,由于调度(例如,选项卡是否处于活动状态,甚至在操作系统可以通知浏览器的范围内可见),甚至只是因为一些 JS 代码花费的时间比您指示的时间长完成的时间间隔,因此您的超时在完成之前实际上无法触发(因为 JS 是单线程的)。
对于 Firefox,请参阅 https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API#Policies_in_place_to_aid_background_page_performance,了解在计时器上执行哪种限制,对于 Chrome,请参阅 https://developers.google.com/web/updates/2017/03/background_tabs
(对于任何其他浏览器,Web 搜索应该会找到类似的文档。
但是,请考虑选项卡成为后台进程意味着什么:如果您的用户看不到您的选项卡,您为什么需要更新任何内容?您的用户将无法看到这些更新。相反,请考虑在选项卡变得不可见时暂停纯视觉任务,然后在选项卡再次可见时恢复它们,并使用时钟时间检查来确定"事情是否需要发生"。
事实上,如果您使用setInterval
或setTimeout
,即使在前台选项卡上执行此操作也很重要:连续 10 次setTimeout(..., 100)
并不意味着一旦完成就会整整 1 秒,这意味着当我们完成时至少晚了 1 秒,但我们可以很容易地在第 7 或第 8 次超时触发时达到"一秒后"标记,因为 JS 是单线程的, 如果某个任务花费了一段时间,则在该任务完成之前不会触发超时。因此,无论如何,您至少需要为此更新代码。
可能是因为 useEffect 调用在第一次渲染后使用 clearInterval 函数。以下是useEffect
的清理如何使用返回的函数 - 使用钩子的示例。