(前端面试题)详解 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、开发者颜色值转换工具   推荐:★★★★★

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

相关文章
|
27天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
24天前
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
springboot解决js前端跨域问题,javascript跨域问题解决
|
1月前
|
JSON JavaScript 前端开发
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
本文介绍了JSONP的工作原理及其在解决跨域请求中的应用。首先解释了同源策略的概念,然后通过多个示例详细阐述了JSONP如何通过动态解释服务端返回的JavaScript脚本来实现跨域数据交互。文章还探讨了使用jQuery的`$.ajax`方法封装JSONP请求的方式,并提供了具体的代码示例。最后,通过一个更复杂的示例展示了如何处理JSON格式的响应数据。
35 2
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
|
27天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
39 5
|
25天前
|
缓存 前端开发 JavaScript
JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式
本文深入解析了JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式(Hash路由和History路由)、优点及挑战,并通过实际案例分析,帮助开发者更好地理解和应用这一关键技术,提升用户体验。
63 1
|
29天前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
34 4
|
1月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
110 1
|
1月前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
40 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
JavaScript 前端开发 小程序
javascript setinterval 正确的语法
前几天我用setinterval 写了一个小程序,这个setinterval是用来干什么的我就不解释了。 写的方法在其它的浏览器里都能用,后来测试组的同事拿去一测就出了问题。
826 0
|
28天前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
25 1
JavaScript中的原型 保姆级文章一文搞懂