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

简介: (前端面试题)详解 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 要长
  1. 对于 周期性调度 的需求(即:重复的定时器),使用“嵌套的 setTimeout ”要比使用 setInterval

What?

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

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

// 使用 setInterval ↓↓↓↓↓↓
let intervalTimerId = setInterval(() => {
  console.log('tick')
}, 2000);
// 使用嵌套的 setTimeout ↓↓↓↓↓↓
function tick() {
  console.log('tick');
  timerId = setTimeout(tick, 2000);
}
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从诞生开始就选择了单线程执行。在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行。

栗子:

function test() {
  for (var i = 0; i < 500000; i++) {
    var div = document.createElement('div');
    div.setAttribute('id', 'testDiv');
    document.body.appendChild(div);
    document.body.removeChild(div);
  }
}
setInterval(test, 10);
var start = new Date();
console.log('start:', start.getMinutes() + ':' + start.getSeconds() + ':' + start.getMilliseconds())
var timer = setTimeout(function() {
  var end = new Date();
  console.log('end:', end.getMinutes() + ':' + end.getSeconds() + ':' + end.getMilliseconds())
}, 1000);

打印出来的是:

start: 15:54:611
end: 15:57:73

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

偏差接近 3s

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

对于第二个结论

let i = 1;
setInterval(function() {
  func(i++);
}, 100);

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

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

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

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

setInterval(() => {
  var time = new Date();
  console.log('time:', time.getMinutes() + ':' + time.getSeconds() + ':' + time.getMilliseconds())
  function test() {
    for (var i = 0; i < 50000000; i++) {
      var div = document.createElement('div');
      div.setAttribute('id', 'testDiv'+i);
      document.body.appendChild(div);
      document.body.removeChild(div);
    }
  }
  test();
}, 1000);

打印出来的是:

隔了差不多 3 分钟!

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

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

let i = 1;
setTimeout(function run() {
  func(i++);
  setTimeout(run, 100);
}, 100);

  程序员面试题库分享

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

地址:前端面试题库

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

地址:前端技术导航大全

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

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

相关文章
|
6天前
|
数据可视化 前端开发 JavaScript
前端框架与库-D3.js数据可视化基础
【7月更文挑战第21天】D3.js是Web开发中创建动态、交互图表的利器,适用于从基础条形图到复杂地理热力图的广泛需求。核心概念涉及数据绑定至DOM,支持动态更新。初学者常遇难题包括不当数据绑定、选择器误用、过渡动画过量及坐标轴配置失误。避免策略需善用`.data()`, `.enter().append()`, `.exit().remove()`管理数据,熟知选择器差异,适度应用`.transition()`, 并精准设定坐标轴。示例条形图代码展示了数据绑定至`&lt;rect&gt;`元素的过程,奠定基础,助你进阶复杂项目。
|
10天前
|
Web App开发 存储 JavaScript
前端如何学习Node.js及Node.js的主要用途
【7月更文挑战第16天】 学习Node.js对前端开发者至关重要,涉及理解其基于V8的运行时环境、JavaScript基础、安装与验证、核心模块(如fs、http、path)及npm管理。实践项目,如用Express建服务器,参与开源,深入学习异步编程和事件循环。Node.js用于服务器开发、构建工具、本地开发服务器和实时应用,提升全栈能力。借助官方文档和各种资源加速学习。
20 4
|
13天前
|
缓存 JavaScript 前端开发
前端框架与库 - Vue.js基础:模板语法、数据绑定
【7月更文挑战第14天】Vue.js 是渐进式框架,以简洁API和高效数据绑定知名。本文聚焦模板语法与数据绑定,解释常见问题和易错点,助力初学者避坑。模板语法中,{{ expression }} 用于渲染值,v-bind/: 用于动态绑定属性。数据绑定涉及文本、属性和事件,注意v-model适用于表单元素,计算属性有缓存。理解正确用法,借助文档和IDE,可提升开发质量和效率。善用Vue.js,打造响应式UI。
|
12天前
|
JavaScript 前端开发 API
前端框架与库 - Vue.js 组件与路由
【7月更文挑战第15天】Vue.js 框架以简洁API和高效DOM更新著名,组件和路由是构建应用的关键。组件是自包含的实例,常见问题包括命名冲突、作用域混淆和状态管理。要避免这些问题,可使用命名空间、明确数据绑定和事件,以及采用Vuex管理状态。Vue Router提供声明式路由,常见挑战包括路由守卫、动态路由参数和懒加载配置。正确使用路由守卫、处理动态参数和实现代码分割能优化路由管理。提供的代码示例展示了基本组件和路由配置。
|
15天前
|
缓存 前端开发 JavaScript
高级前端常见的面试题?
【7月更文挑战第11天】 **高级前端面试聚焦候选人的技术深度、项目实战、问题解决及技术趋势洞察。涉及React/Vue生命周期、Redux/Vuex状态管理、Webpack优化、HTTP/HTTPS安全、性能提升策略、PWA、GraphQL、WebAssembly、安全性议题及项目管理。通过回答,展现候选人技术广度与应对复杂场景的能力。**
28 1
|
21天前
|
JavaScript 前端开发 数据可视化
js 实现动画的两种方案对比:setTimeout vs RAF (requestAnimationFrame)
js 实现动画的两种方案对比:setTimeout vs RAF (requestAnimationFrame)
25 2
|
21天前
|
前端开发 NoSQL 数据库
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
|
4天前
|
缓存 JavaScript 前端开发
js高频面试题,整理好咯
中级前端面试题,不低于12k,整理的是js较高频知识点,可能不够完善,大家有兴趣可以留言补充,我会逐步完善,若发现哪里有错,还请多多斧正。
|
16天前
|
移动开发 前端开发 JavaScript
前端常见的面试题都有那些?
【7月更文挑战第10天】 前端面试涵盖HTML5新特性、CSS盒模型、JS事件传播、Vue的双向绑定、React生命周期、性能优化策略、浏览器解析流程及安全知识等。例如,HTML5新增video/audio元素、CSS选择器优先级计算、闭包功能、async/await处理异步、Vue通过Object.defineProperty实现数据绑定、React组件生命周期的关键阶段、前端优化如CDN和资源压缩,以及浏览器如何构建渲染树。面试还可能涉及XSS/CSRF防护和框架选择考量。准备面试需全面理解基础概念并结合实践经验。
17 0
|
21天前
|
JavaScript
JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)
JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)
41 0