为了账号安全,请及时绑定邮箱和手机立即绑定

前端进阶之setTimeout 倒计时为什么会出现误差?

标签:
Html5

线程与进程

相信大家经常会听到一句话,就是 “JS是单线程的”,可是什么是 线程,什么又是 单线程,有 多线程 吗?

定义

讲到线程,那么肯定也得说一下进程。其实在本质上,两个名词都是 CPU 工作时间片的一个描述。

进程(process) 指的是CPU 在 运行指令及加载和保存上下文所需的时间,放在应用上是指计算机中已运行的程序。

线程(thread) 是操作系统能够进行运算的最小单位。它被包含在 进程 之中,描述了执行一段指令所需的时间。

  • 单线程:按代码书写顺序从头到尾,一行一行地执行代码,如果其中一行代码报错,那么剩下代码将不再执行。容易阻塞代码。

  • 多线程:代码运行的环境不同,各线程独立,互不影响,避免阻塞。

浏览器中的线程

浏览器中的线程分了以下几类:

  • JS线程

  • UI线程

  • event线程

  • 定时器线程

  • http线程

执行栈

执行栈可以理解为是用来存储函数调用的栈,遵循先进后出的原则。

事件循环

node端

Node 的 Event Loop 分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。

Event Loop 6 个阶段:

  1. timers

  2. I/O callbacks

  3. idle, prepare

  4. poll

  5. check

  6. close callbacks

浏览器端

浏览器端 的情况与 node端 的情况相仿,当我们执行 JS 代码的时候其实就是往执行栈中放入函数,当遇到异步的代码时,会被挂起并在需要执行的时候加入到 Task(有多种 Task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行。

  • 微任务(microtask)

    • process.nextTick

    • promise

    • Object.observe(曾经是提案,如今已经废除)

    • MutationOberver

  • 宏任务(macrotask)

    • script

    • setTimeout

    • setInterval

    • setImmediate

    • I/O

    • UI渲染

执行顺序如下:

  1. 执行同步代码,这是宏任务

  2. 执行栈为空,查询是否有微任务要执行

  3. 必要时渲染UI

  4. 进行下一轮的 EventLoop ,执行宏任务中的异步代码

setTimeout 误差

上面讲了定时器是属于 宏任务(macrotask) 。如果当前 执行栈 所花费的时间大于 定时器 时间,那么定时器的回调在 宏任务(macrotask) 里,来不及去调用,所有这个时间会有误差。

我们看以下代码:

setTimeout(function () {
	console.log('biubiu');
}, 1000);

某个执行时间很长的函数();

如果定时器下面的函数执行要 5秒钟,那么定时器里的log 则需要 5秒之后再执行,函数占用了当前 执行栈 ,要等执行栈执行完毕后再去读取 微任务(microtask),等 微任务(microtask) 完成,这个时候才会去读取 宏任务(macrotask) 里面的 setTimeout 回调函数执行。setInterval 同理,例如每3秒放入宏任务,也要等到执行栈的完成。

还有一种情况如下:

setTimeout(function() {
    setTimeout(function() {
        setTimeout(function() {
            setTimeout(function() {
                setTimeout(function() {
                    setTimeout(function() {
                        console.log('嘤嘤嘤');
                    }, 0);
                }, 0);
            }, 0);
        }, 0);
    }, 0);
}, 0);

在最新的规范里有这么一句: If nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4.

所以意思就是意思就是如果timeout嵌套大于 5层,而时间间隔小于4ms,则时间间隔增加到4ms。



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
109
获赞与收藏
602

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消