在前端面试中,JavaScript 定时器相关的知识是一个常考的重点,它涉及到 JavaScript 的单线程特性、异步执行机制等重要概念。下面我们就来详细梳理一下关于 JavaScript 定时器的相关知识。
一、JavaScript 单线程特性
JavaScript 是单线程的,这意味着它只有一个主线程来执行代码。这就导致如果在主线程上有一个耗时的操作,后续的代码都需要等待这个操作完成才能执行。例如,如果有一个无限循环:
arduino
while(true){
}
在这个循环执行期间,其他的代码都无法执行,包括定时器。
二、 setTimeout
函数
基本概念
setTimeout
是一个异步执行的计时器,它接收两个参数:一个回调函数和一个时间(以毫秒为单位)。回调函数会被放入事件循环(event loop)中,但不会立即执行,而是会在主线程执行完后,等待指定的时间后再执行。
示例代码
xml
<!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">提前关闭setTimeout定时器</button>
<button id="btn">关闭定时器</button>
<script>
const timeout = setTimeout(function(){
console.log('---')
}, 1000);
// 同步代码
console.log(123);
const btn = document.getElementById('btn');
const btn2 = document.getElementById('btn2');
btn.addEventListener('click', function(){
clearTimeout(interval);
});
btn2.addEventListener('click', function(){
clearInterval(timeout);
});
const interval = setInterval(function(){
console.log('哈....')
}, 1000);
</script>
</body>
</html>
注意事项
- 即使
setTimeout
的时间设置为 0 秒,它也不会立即执行,而是会在主线程执行完后再执行。 setTimeout
并不一定会在指定的时间后立即执行,因为它需要等待主线程上的代码执行完毕。
定时器 ID
setTimeout
函数会返回一个定时器 ID,这个 ID 可以用于后续关闭定时器,使用 clearTimeout
函数,传入定时器 ID 即可关闭定时器。
三、 setInterval
函数
setInterval
函数用于每隔指定的时间重复执行一个回调函数。它的使用方式和 setTimeout
类似,同样接收一个回调函数和一个时间间隔(毫秒)作为参数。
示例代码
javascript
const interval = setInterval(function(){
console.log('哈....')
}, 1000);
关闭定时器
可以使用 clearInterval
函数来关闭 setInterval
创建的定时器,需要传入定时器 ID。
四、 高频面试题------使用 setTimeout
实现 setInterval
实现思路
可以使用递归调用 setTimeout
来模拟 setInterval
的功能。
示例代码
xml
<!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>
function customSetInterval(fn, time) {
let intervalId = null;
function loop() {
intervalId = setTimeout(() => {
fn();
loop();
}, time);
}
loop();
return () => clearTimeout(intervalId);
}
const interval = customSetInterval(function() {
console.log('定时器ing...');
}, 1000);
setTimeout(() => {
interval();
}, 5000);
</script>
</body>
</html>
代码解释
-
函数定义与参数 :
customSetInterval
函数接收两个参数,fn
是要定期执行的回调函数,time
是执行回调函数的时间间隔(单位为毫秒)。 -
变量声明 :
let intervalId = null;
声明了一个变量intervalId
,用于存储setTimeout
返回的定时器 ID,初始值为null
。 -
内部递归函数
loop
:intervalId = setTimeout(() => { fn(); loop(); }, time);
:在time
毫秒后执行箭头函数,箭头函数内部先调用fn()
执行回调函数,然后递归调用loop()
函数,以实现定时重复执行的效果。- 每次调用
setTimeout
都会返回一个新的定时器 ID,并将其赋值给intervalId
。
-
启动循环 :
loop();
调用loop
函数,启动定时器的循环执行。 -
返回清除定时器的函数 :
return () => clearTimeout(intervalId);
返回一个箭头函数,该函数用于清除定时器。调用这个返回的函数时,会传入intervalId
给clearTimeout
函数,从而停止定时器的执行。 -
使用自定义定时器:
-
const interval = customSetInterval(function() { console.log('定时器ing...'); }, 1000);
调用customSetInterval
函数,传入一个匿名函数作为回调函数,以及时间间隔1000
毫秒(即 1 秒),并将返回的清除定时器的函数赋值给interval
。 -
setTimeout(() => { interval(); }, 5000);
使用setTimeout
函数,在 5000 毫秒(即 5 秒)后调用interval()
函数,从而停止定时器的执行。
-
五、结语
通过以上内容的学习,我们对 JavaScript 定时器的相关知识有了更深入的理解,这些知识在前端面试中是非常重要的,希望大家能够掌握。