setTimeout和setInterval实现倒计时的区别

更新日期: 2019-12-28 阅读: 2.9k 标签: 区别

前言

这是一个由于倒计时插件出现bug而出现的文章,导致我努力去寻找这个原因的源头,最后终于发现了新大陆(先事先展示一下新大陆的结论):

setTimeout和setInterval都有误差

以1秒为例,setInterval会每次准时在1秒钟的时候将微任务推入主任务队列,导致如果某次本该在时间(1s=1000ms)1998ms的时候改变数据,但是变成2000ms的时候改变数据。它(setInterval)在下一次循环的2998ms依然会改变数据,以此类推,导致此时会展示(这里考虑省略小数点,四舍五入同样原理):2000ms(2s)->2998ms(2s)->3998ms(3s)->4998ms(4s)->6000ms(6s)->6998ms(6s)

以1秒为例,setTimeout会每次都在1秒钟后将微任务推入主任务队列,导致如果某次本该在时间(1s=1000ms)1998ms的时候改变数据,以此类推,导致此时会展示(这里考虑省略小数点,四舍五入同样原理):1998ms(1s)->3000ms(3s)->4002ms(4s)->5004ms(5s)->6006ms(6s)->7006ms(7s)


细究原理

首先,你得先了解js的Event Loop机制里面的微任务和宏任务,不然,我们的沟通缺少了一个平台。

然后,就是问题的关键点了,为什么会出现这样的情况呢?

答案:以1秒为例,setInterval和setTimeout都会在异步模块运行,但是setInterval会每次都刚刚好1s钟的时候,将微任务队列的函数,交于任务队列进行执行。如果setInterval第一次1.004s的时候将任务推进队列,那么这时候setInterval的每次的误差会是在0.996s-1.01s内波动,而setTimeout每次的误差值都会大于1s。这里我画个图,相信大家就能够明白setInterval实现倒计时的不好之处(图中进制以省略小数点为准,四舍五入同理)



附上一个react hooks版本的倒计时组件给大家

// 倒计时组件
import React, { useState, useEffect } from 'react';

interface CountdownInfo {
  hour: number;
  minute: number;
  second: number;
  day: number;
}

interface CountdownProps {
  sec: number;
  render: (data: CountdownInfo) => React.ReactNode;
  onEnd: () => void;
}

const Countdown: React.FC<CountdownProps> = ({ sec, render, onEnd }) => {
  const [endTime, setEndTime] = useState(new Date(Date.now() + sec*1000));
  const [countdownInfo, setCountdownInfo] = useState({
    hour: 0,
    minute: 0,
    second: 0,
    day: 0,
  } as CountdownInfo);

  const tick = () => {
    const seconds = Math.floor((endTime.getTime() - Date.now())/1000);
    const day = Math.floor(seconds / 86400);
    const hour = Math.floor((seconds % 86400) / 3600);
    const minute = Math.floor((seconds % 3600) / 60);
    const sec = seconds % 60;
    setCountdownInfo({
      day,
      hour,
      minute,
      second: sec,
    } as CountdownInfo);

    if(seconds <= 0) {
      onEnd && onEnd();
    } else {
      window.setTimeout(tick, 1000);    // 时间不截至一直倒计时
    }
  }

  useEffect(() => {
    setEndTime(new Date(Date.now() + sec*1000));
  }, [sec]);
  useEffect(() => {
    tick(); // 初始化倒计时
  }, []);
  return render(countdownInfo) || null;
}

export default Countdown;

引用方式

const renderCountdown = ({day, hour, minute, second}): React.ReactNode => {
    return (
      <div>
        <span>{ day > 0 ? (day+'天') : null }</span>
        <span>hour</span>:
        <span>minute</span>:
        <span>second</span>
      </div>
    );
}

const onEnd = () => {
    console.log("倒计时结束")
}

<Countdown 
    sec={100} 
    render={renderCountdown} 
    onEnd={onEnd}
/>

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/7945

相关推荐

AR / MR / VR / XR有什么区别?

VR能让人完全沉浸在虚拟环境中;AR能创建一个叠加在虚拟内容的世界,但不能与真实环境交互; MR则是虚拟与现实的混合体,它能创造出可以与真实环境交互的虚拟物体。最后,XR则是包括三种“现实”(AR,VR,MR)的术语。

Js插件、 组件、类库、框架的区别

框架和类库等概念的出现都是源于人们对复用的渴望。“不要重复发明轮子”,成了软件界的一句经典名言。从最初的单个函数源代码的复用,到面向对象中类的复用(通常以类库的形式体现)

理解screenX,clientX,pageX,offsetX,pageXoffset的区别

event.screenX、event.screenY鼠标相对于用户显示器屏幕左上角的X,Y坐标。标准事件和IE事件都定义了这2个属性,event.clientX、event.clientY鼠标相对于浏览器可视区域的X,Y坐标

初中高级工程师的区别?

我们知道程序员分 初级,中级, 高级, 这个概念, 并不是以工作年限作为分类依据的。 也就是说, 级别和你工作多少年没有必然的联系。一个初级工程师可能工作很多年依然是初级工程师, 也有的工程师, 工作短短两三年, 就跻身高级工程师的行列。

互联网、局域网、万维网三者区别?

互联网是指多台设备(如计算机、手机等)通过特定通信协议(TCP/IP、IPX/SPX、NetBIOS、NetBEUI、Apple Talk)组成的网络。一般可分为以下三种:局域网LAN(Local Area Network):一般不大于10公里,而且通常只使用一种传输介质

js中.和[]的区别

在js中,对象属于是键值对的集合,在上面这个代码中,name就属于是key,而‘残梦‘就是value。总之一句话: []更强大,.就是用起来更加习惯一些,一开始用[]的时候总是会当成数组,需要注意一下

CSS中zoom和scale的差异

zoom和scale这两个东西都是用于对元素的缩放,但两者除了兼容性之外还有一些不同的地方。zoom缩放会将元素保持在左上角,而scale默认是中间位置,可以通过transform-origin来设置。

*.min.js跟*.js的区别

js是JavaScript 源码文件, .min.js是压缩版的js文件。减小体积 .min.js文件经过压缩,相对编译前的js文件体积较小,传输效率快。防止窥视和窃取源代码

package.json中^和~的区别

webpack 项目的package.json 文件列出了项目所依赖的插件和库,同时也给出了对应的版本说明,但是在版本说明前面还有个符号:‘^‘(插入符号)和‘~‘(波浪符号),总结了下他们之间的区别:

PTN与SDH的区别?

SDH是基于TDM技术,主要用于传输语音,此外采用GFP封装来传输IP包,物理介质为光纤。PTN是采用DWDM技术,主要用于传输IP包、以太网帧,此外采用MPLS-TP技术来实现PWE3伪线

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!