稀土掘金技术社区 2024年12月13日
“你会使用 setTimeout 来实现 setInterval 吗?”来自于面试官的灵魂拷问
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了JavaScript中定时器setTimeout和setInterval的原理与应用。文章首先介绍了JavaScript的单线程和事件循环机制,解释了setTimeout和setInterval的基本功能、参数和返回值,并详细分析了它们在异步执行中的行为。文章通过代码示例展示了如何理解setTimeout的异步执行,并解释了定时器并非总是准时执行的原因。此外,还介绍了如何使用clearInterval来取消定时器。最后,文章通过一个面试题,详细讲解了如何使用setTimeout来实现setInterval的功能,并提供了完整的代码示例和流程分析。这为前端开发者深入理解定时器机制提供了有力的帮助。

⏱️setTimeout和setInterval都是JavaScript中用于定时执行代码的函数,但setTimeout只执行一次,而setInterval会重复执行。

🔄JavaScript是单线程的,通过事件循环机制处理异步操作。setTimeout的回调函数会在主线程执行完后放入回调队列,等待执行,因此并非立即执行。

🛑定时器并非总是准时执行,当主线程繁忙时,定时器回调函数的执行会被延迟。可以使用clearInterval来取消定时器,避免不必要的执行。

💡面试题:可以通过setTimeout递归调用自身来实现setInterval的效果。同时,返回清除定时器的函数,以便在需要时停止定时任务。

原创 Danta 2024-12-12 08:30 重庆

点击关注公众号,“技术干货” 及时达!

前言

上一世,我站在了梦想的门前——一家心仪已久的大厂就在眼前。然而,命运似乎喜欢开玩笑,在最后一轮面试中,面试官抛出了一个看似简单却足以改变一切的问题:“你能用 setTimeout 实现 setInterval 吗?”那一瞬间,我的心跳仿佛停滞,脑海中一片空白。最后,我只能眼睁睁地看着这份机会溜走,带着遗憾和不甘,噢不!我的大厂梦寄你太美了。

屏幕录制 2024-12-05 124213.gif

这一世,我重活一遍,决不能在这里倒下,面试官,你才是挑战者!

简述:

本文将详细讲解:定时器中的setTimeoutsetInterval,以及它们的运行顺序,和最后的压轴面试题:使用 setTimeout 来实现 setInterval 。我会先介绍完基础知识,最后连串起来手撕面试题,如果兄弟们等不及的可以直接跳到最后看如何实现。

定时器:

JavaScript 是「单线程语言」,它只有一个主线程,所有任务都在这个线程上执行,这意味着一次只能做一件事。为了处理异步操作,比如计时器、网络请求等,JavaScript 使用了事件循环(Event Loop)机制。当一个异步操作完成时,它会被放入回调队列中等待主线程空闲时再执行。

setTimeout 和 setInterval  函数

之所以把它们放在一起讲,是因为其实它的功能有点相似,一起讲便于大家更好的理解。

功能对比
参数结构

两者都接受相似的参数:

    「callback」:当计时器到期时要执行的函数。

    「time」:对于 setTimeout 是延迟时间,对于 setInterval 是每次执行之间的间隔时间,以毫秒为单位。非数字值会被视为 0,负数也会被当作 0 处理。

    「[arg1, arg2, ...]」 :可选参数,这些参数将在调用回调函数时传递给它。

返回值

如何理解setTimeout 是异步执行的计时器,会在主线程执行完之后再执行?

我们可以通过一段代码来解释:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>定时器</title></head><body>       <script>       setTimeout(function(){            console.log('hello world');         },10000)                  console.log(123)      </script></body></html>

大家可以猜猜结果:

123hello world

「解释:」 兄弟们肯定有疑问,为什么不是先执行定时器,再输出123呢?这样的想法也没错,JS执行机制:从上到下嘛。但是换个思想,假如说:定时器的时间是接近于「无限长」,如果先执行定时器,那么后面的程序是不是永远不可能得到运行了。

显然开发者不会允许这种情况发生,那么setTimeout,它的运行其实是异步的,也就不是从上到下,而是先把callback 函数 放入 event loop,然后「当主线程全部执行完后」,再来执行放入 event loop中的callback 函数

所以也就引出了一个问题:是否定时器会按时输出函数中的内容呢?

setTimeout一定会在指定时间后执行吗?

答案当然是否定的!为什么呢?

    当你的主线程程序是无限次的循环时,那么主线程没有结束,就不会去执行定时器中的回调函数了。

比如:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>定时器</title></head><body>   <button id="btn2">停止</button>      <script>         setTimeout(function(){            console.log('hello world');         },1000);          while(true){         }      </script></body></html>

    就是如果你在网页中打开,定时器启动但是你在未达到定时器时间时,就关闭了网页,这样也执行不了。

如何关闭定时器呢?

关闭定时器,这时候就要用到定时器自带的返回值了。

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title></head><body>    <button id="btn">关闭定时器</button>    <script>        const interval=setInterval(function(){        console.log('hello world');    },1000)    console.log(interval)    const btn=document.getElementById('btn');    btn.onclick=function(){        clearInterval(interval);    }      </script></body></html>

运行以下代码,我们可以看到结果:

我们可以看到,当没点击停止按钮时,hellow world一直在输出,点击后就停止了。

「流程分析:」

    「设置定时器」:在<script>标签内的代码被执行时,首先通过setInterval函数创建了一个定时器。这个定时器每秒(1000毫秒)都会触发一次匿名函数,该匿名函数的作用是向浏览器的控制台输出字符串'hello world'。setInterval返回一个唯一的标识符(ID),用来标识这个定时器,这里被存储在变量interval中。

    「打印定时器ID」:紧接着,console.log(interval)这行代码将定时器的ID输出到控制台。

    「获取按钮元素」:使用document.getElementById('btn')获取页面上的按钮元素,并将其赋值给btn变量。

    「为按钮添加点击事件处理器」:为btn按钮设置了点击事件处理函数。当用户点击按钮时,会调用clearInterval(interval)来停止定时器,从而阻止'hello world'继续被输出到控制台。

    「用户交互」:一旦页面加载完毕,如果用户点击了“关闭定时器”按钮,就会触发上述的点击事件处理函数,定时器将会被清除,之后就不会再有'hello world'的消息输出到控制台了。

当我们拿捏了以上的知识点,我们就可以开始解面试题了。

举个栗子

如何setTimeout实现setInterval?

首先我们来分析一下:这是一道场景编程题,要求我们去使用setTimeout,然后实现setInterval,当时我看到这题的时候,想到的是使用setTimeout去递归自己,但是好像不太行。

好了来上代码吧!

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title></head><body>    <script>     function customSetTimeout(fn,time){        let intervalID=null        function loop(){          intervalID= setTimeout(()=>{            fn();            loop();           },time)        }        loop();        return ()=>clearTimeout(intervalID);     }     const interval=customSetTimeout(function(){        console.log('hello world')     },1000)          setTimeout(()=>{        interval();     },5000)
</script></body></html>

流程分析:

    「定义customSetTimeout函数」

    「启动首次循环」

    「返回清除定时器的函数」

    「使用customSetTimeout函数」

    「设定定时器以停止customSetTimeout

总结

如此一来,我们就实现了使用使用setTimeout 来实现setInterval,并且定时的关闭了这个功能。

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

setTimeout setInterval JavaScript定时器 异步编程 事件循环
相关文章