• (前端面试题)详解 JS 的 setTimeout 和 setInterval 两大定时器


     

       程序员面试题库分享

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

    2、前端技术导航大全      推荐:★★★★★

    地址:前端技术导航大全

    3、开发者颜色值转换工具   推荐:★★★★★

    地址 :开发者颜色值转换工具

    携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

    概述

    下文主要介绍 JS 中 setTimeout 和 setInterval 两大定时器的区别和执行细节,如解析上有错误,欢迎各位在评论区指出 ( ̄▽ ̄)~*

    结论

    1. setTimeout 是期望推迟(delay)ms后执行函数, setInterval 则是期望间隔(delay)ms就执行一次函数
      • 注意,这里两个函数都是期望推迟或期望间隔,不能保证准确推迟或准确间隔
      • 说人话:
        • setTimeout(func, 1000)期望推迟 1000ms 后执行 func 函数,但有实际结果可能要比 1000ms 要长
        • setInterval(func, 1000),期望间隔 1000ms 后执行 func 函数,但有实际结果可能要比 1000ms 要长
    2. 对于 周期性调度 的需求(即:重复的定时器),使用“嵌套的 setTimeout ”要比使用 setInterval 好

    What?

    对于第二个结论,周期性调度有两种方式

    一种是使用 setInterval,另外一种就是嵌套的 setTimeout,就像这样:

    1. // 使用 setInterval ↓↓↓↓↓↓
    2. let intervalTimerId = setInterval(() => {
    3. console.log('tick')
    4. }, 2000);
    5. // 使用嵌套的 setTimeout ↓↓↓↓↓↓
    6. function tick() {
    7. console.log('tick');
    8. timerId = setTimeout(tick, 2000);
    9. }
    10. let timeoutTimerId = setTimeout(tick, 2000);

    Why?

    对于第一个结论

    之所以说 setTimeout(func, 1000),是期望推迟 1000ms 后执行 func 函数,是因为 js 是运行在单线程的环境中,也就是说,js 在一瞬间只能处理一件事情。推迟 1000ms 后执行 func 函数,但在达到 1000ms 的那个瞬间,有可能在处理其它事情,所有就不能按期望,在达到 1000ms 的那个瞬间执行 func 函数。

    说人话:比如你约好了朋友晚上 7 点一起下班去吃饭,结果 6 点 59 分,突然有一个紧急 bug 需要处理,你就没办法准时赴约

    专业一点的说法: JavaScript 有一个基于“Event Loop”并发的模型(不是并行)。前者是逻辑上的同时发生,而后者是物理上的同时发生。所以,单核处理器也能实现并发,如下图:

    之前一直想为什么 js 要设计成单线程运行,现在找到一种说法感觉还挺合理: JavaScript的主要用途是与用户互动,以及操作DOM。若以多线程的方式,则可能出现冲突。假设有两个线程同时操作一个DOM元素,线程1要求浏览器删除DOM,而线程2却要求修改DOM样式,这时浏览器就无法决定采用哪个线程的操作。当然,我们可以为浏览器引入“锁”的机制来解决这些冲突,但大大提高复杂性,所以 JavaScript从诞生开始就选择了单线程执行。在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行。

    栗子:

    1. function test() {
    2. for (var i = 0; i < 500000; i++) {
    3. var div = document.createElement('div');
    4. div.setAttribute('id', 'testDiv');
    5. document.body.appendChild(div);
    6. document.body.removeChild(div);
    7. }
    8. }
    9. setInterval(test, 10);
    10. var start = new Date();
    11. console.log('start:', start.getMinutes() + ':' + start.getSeconds() + ':' + start.getMilliseconds())
    12. var timer = setTimeout(function() {
    13. var end = new Date();
    14. console.log('end:', end.getMinutes() + ':' + end.getSeconds() + ':' + end.getMilliseconds())
    15. }, 1000);

    打印出来的是:

    1. start: 15:54:611
    2. end: 15:57:73

    正常来说 end 打印出来的应该是 15:55:611 才对

    偏差接近 3s

    》》》》》》》》》》》》》》》》》》

    对于第二个结论

    1. let i = 1;
    2. setInterval(function() {
    3. func(i++);
    4. }, 100);

    以上代码,我们原本的想法是,每隔 100ms 执行一次 func 函数,但实际上 func(1) 和 func(2) 之间的间隔不是 100ms,因为 func 函数的执行本来就是需要消耗时间的

    使用 setInterval 时,func 函数的实际调用间隔要比代码中设定的时间间隔要短!(上图所示)

    极端情况下,如果函数每次执行时间都超过 delay 设置的时间,那么每次调用之间将完全没有停顿,而时间间隔已经不取决于delay 设置的时间,而是 func 的执行时间。例如以下代码:↓↓↓↓↓↓

    ps:以下代码有毒,要跑很久,可能会卡死浏览器

    1. setInterval(() => {
    2. var time = new Date();
    3. console.log('time:', time.getMinutes() + ':' + time.getSeconds() + ':' + time.getMilliseconds())
    4. function test() {
    5. for (var i = 0; i < 50000000; i++) {
    6. var div = document.createElement('div');
    7. div.setAttribute('id', 'testDiv'+i);
    8. document.body.appendChild(div);
    9. document.body.removeChild(div);
    10. }
    11. }
    12. test();
    13. }, 1000);

    打印出来的是:

    隔了差不多 3 分钟!

    正常来说,应该是每个差不多 100ms 打印一次,但因为中间加了一个超级耗时的任务,所以时间间隔拉得很长

    如果期望 func 隔 100ms 执行一次的话(再强调一遍,是期望,不是绝对,详细见结论 1),最好是使用嵌套的 setTimeout

    1. let i = 1;
    2. setTimeout(function run() {
    3. func(i++);
    4. setTimeout(run, 100);
    5. }, 100);

       程序员面试题库分享

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

    2、前端技术导航大全      推荐:★★★★★

    地址:前端技术导航大全

    3、开发者颜色值转换工具   推荐:★★★★★

    地址 :开发者颜色值转换工具

  • 相关阅读:
    如何成为AI工程师
    Java进阶知识点及案例总结(续2)
    停车系统源码
    ABB机器人数组码垛精解
    Mysql5.7主从复制搭建
    如何用devtools快速开发一个R语言包?
    在华为和比亚迪干了5年测试,月薪25K,熬夜总结出来的划水经验.....
    Android自定义Drawable---灵活多变的矩形背景
    Windows下安装并启动Redis
    决赛名单公布!亚马逊云科技2022 AI For Good决赛酣战在即!
  • 原文地址:https://blog.csdn.net/weixin_42981560/article/details/126343450