面试题答案
一键面试1. 执行机制不同点
- setTimeout:设置一个定时器,在指定的延迟时间(单位:毫秒)过后,将回调函数添加到任务队列中。当调用栈为空时,任务队列中的回调函数才会被压入调用栈执行。它只执行一次回调函数。例如:
setTimeout(() => {
console.log('这是setTimeout的回调');
}, 2000);
上述代码中,2秒(2000毫秒)后console.log('这是setTimeout的回调');
会被添加到任务队列,等调用栈空闲时执行。
- setInterval:同样设置一个定时器,按照指定的时间间隔(单位:毫秒)不断地将回调函数添加到任务队列中。只要页面不关闭或者没有调用
clearInterval
取消定时器,回调函数就会持续被添加到任务队列,当调用栈空闲时就执行。例如:
let count = 0;
let intervalId = setInterval(() => {
console.log(`这是setInterval的回调,执行次数: ${++count}`);
if (count === 5) {
clearInterval(intervalId);
}
}, 1000);
上述代码中,每1秒(1000毫秒)console.log(
这是setInterval的回调,执行次数: ${++count});
就会被添加到任务队列,等调用栈空闲时执行,直到count
等于5时通过clearInterval
停止定时器。
2. 场景及因差异导致的不同结果
- 动画场景:如果要创建一个平滑过渡的动画,使用
setInterval
可能会导致动画卡顿。因为setInterval
不管上次回调函数是否执行完毕,都会按照固定间隔时间将新的回调函数添加到任务队列。例如,在一个复杂的动画计算中,上次计算还未完成,新的计算又被添加到任务队列,可能导致动画帧丢失,画面卡顿。而setTimeout
可以在每次动画帧计算完成后,再设置下一次动画帧的时间,保证动画的流畅性。
// 使用setInterval实现动画(可能卡顿)
let pos = 0;
let intervalId = setInterval(() => {
pos += 5;
document.getElementById('element').style.left = pos + 'px';
if (pos >= 200) {
clearInterval(intervalId);
}
}, 50);
// 使用setTimeout实现动画(更流畅)
function animate() {
pos += 5;
document.getElementById('element').style.left = pos + 'px';
if (pos < 200) {
setTimeout(animate, 50);
}
}
animate();
在上述代码中,setInterval
版本可能出现计算还未完成就开始下一次计算的情况,而setTimeout
版本可以确保每次动画计算完成后再开始下一次,使动画更流畅。
- 数据轮询场景:假设要定期从服务器获取最新数据。使用
setTimeout
时,每次获取数据后,再设置下一次获取的时间,这样可以确保每次获取数据的操作都完成后才进行下一次请求。而setInterval
可能在前一次请求还未完成时,就发起了新的请求,造成不必要的资源浪费和数据冲突。
// 使用setTimeout轮询数据
function fetchData() {
// 模拟数据请求
console.log('开始获取数据');
setTimeout(() => {
console.log('数据获取完成');
setTimeout(fetchData, 5000);
}, 2000);
}
fetchData();
// 使用setInterval轮询数据(可能有问题)
let intervalId = setInterval(() => {
console.log('开始获取数据');
setTimeout(() => {
console.log('数据获取完成');
}, 2000);
}, 5000);
在上述代码中,setInterval
版本可能在2秒的数据请求未完成时,5秒后又发起新的请求,而setTimeout
版本可以保证前一次请求完成后再发起新请求。