setTimeout 引申

简介: setTimeout 引申

正文


一、前言


在 JavaScript 中 setTimeoutsetInterval 最常见不过了,用于延迟或者延迟重复处理等。


setTimeout(() => {
  console.log('一秒后执行')
}, 1000)


这个不能再简单的例子,我们可以简单地理解成:一秒后输出对应的字符串。但是这一秒(delay)只是我们所设的预期值,然而实际情况它只是最小延迟时间而已。也就是说最理想情况下,1 秒之后会执行该匿名函数。


Q:那能否在我们所指定的时间执行对应函数呢?


A:严格来说肯定是不行的,有实实在在的误差在里面,平常看起来像是指定时间执行只是因为我们本身无法感知其中的误差而已。倘若误差在可接受范围内,理解成指定时间后执行也是没问题的。

影响它的因素有很多:比如 for 循环、其他异步任务(微任务、宏任务)、浏览器精度等。本质上是因为 JavaScript 的事件循环机制导致的


// 可自行验证一下,能否在一秒后执行?
setTimeout(() => {
  console.log('会在一秒后执行吗?')
}, 1000)
for(let i = 0; i < 10000; i++) {
  console.count('循环次数')
}


我对 setTimeout 的理解是:在指定时间后,将对应函数作为异步任务加入到任务队列中。

对于刚接触 JavaScript 的朋友,可能会错误地理解为:在指定时间后,执行对应函数。这是不对的,上面的例子就能说明问题。

为什么呢?因为可能一秒的时间内 for 循环还没执行完,所以一秒后还没开始执行定时器里面的函数。我们都知道 setTimeout 属于异步任务(宏任务),在执行(下)一个异步任务之前,首先得执行当前完同步任务、微任务(也属于异步任务)、接着更新UI 之后,才会执行(下一个)异步任务。


二、正题


扯得有点多了,今天的话题是:setTimeout 加不加括号,会导致什么不同的结果?

看以下示例:


function foo() {
  console.log('show foo')
}
// 写法一
setTimeout(foo, 3000)
// 写法二
setTimeout(foo(), 3000)
// 两者运行结果一致吗?


  1. delay 设为 300,看起来好像没区别,都能正常输出 show foo,接着往下看。
  2. 若将 delay 设为 3000,仍然都能输出字符串,但有点区别。setTimeout(foo, 3000)在预期的 3s 后输出值。然而setTimeout(foo(), 3000)好像立刻执行了,而不是等 3s 后才输出。
  3. 通过设置不同 delay 值可以更明显地感知其中的区别,越大越明显。


两者区别:

  1. 不加括号:能正常地按照我们所预期的时候执行对应的函数。
  2. 加括号:同样会执行该函数,但它是立即执行,所以不会达到延迟执行的目的。(这点说法不严谨,只是帮助理解,请继续往下看)


造成上面差异的原因是什么呢?


我们改下代码,就很清晰了。


function foo() {
  console.log('show foo')
  return 'console.log("哈哈")'
}
setTimeout(foo(), 3000)
// 结果:立即打印出 show foo,三秒后打印了 “哈哈”。


因为 foo 函数返回值是 console.log("哈哈"),所以 setTimeout(foo(), 3000) 相当于 setTimeout('console.log("哈哈")', 3000) ,所以出现了上面的结果。其实 setTimeout 方法第一个参数除了支持函数之外,还可以是字符串。若是字符串,会使用  eval 去执行。


由于我们最常用的写法是执行一个匿名函数(如setTimeout(() => {}, delay)),没注意的同学,所以可能会忽略加与不加括号的区别。

还有,极不建议使用 setTimeout('String Code', delay) 的形式。因为 eval 通常被用来执行动态创建的代码,如果 eval(...) 中执行的代码包括一个或多个声明(无论变量还是函数),就会对 eval(...) 所处的词法作用域进行修改。避免出现一些意料之外的事情,不建议使用。


三、扩展


1. 当使用 setTimeout() 方法的时候,是否必须执行 clearTimeout() ?
  • setTimeout() 内的函数执行之前,如果想要阻止执行该方法,只能通过 cleartTimeout() 来处理。
  • setTimeout() 内的函数执行之后,执行 clearTimeout() 方法对整个代码流程没有害处,但是是没有必要的。
  • 通常情况,执行 clearInterval() 比执行 clearTimeout() 更实际一些,因为如果不执行 clearInterval(),则 setInterval() 的方法会无限循环执行下去。而 setTimeout() 在一次调用后,就会停止执行(浏览器会自动回收资源)。除非你创建了一个无限循环的 setTimeout()
2. 关于 setTimeout(fn, 0) 的问题

注意,这仍然属于异步任务,指定某个任务在主线程最早可得的空闲时间执行。HTML5 标准中规定了 setTimeout() 的第二个参数的最小值(最短间隔),不得低于 4 毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为 10 毫秒。另外,对于那些 DOM 的变动(尤其是涉及页面重新渲染部分),通常不会立即执行,而是每 16 毫秒执行一次。这时使用 requestAnimationFrame() 的效果要好于 setTimeout() 。


可以看下文章:

目录
相关文章
|
Cloud Native 安全 Java
go和java的比较
go和java的比较
|
移动开发 安全 数据安全/隐私保护
iOS 全局自动化代码混淆工具!支持 cocoapod 组件代码一并混淆
iOS 全局自动化代码混淆工具!支持 cocoapod 组件代码一并混淆
|
计算机视觉
OpenCV-计算轮廓周长cv::arcLength
OpenCV-计算轮廓周长cv::arcLength
327 0
|
小程序 数据库 开发者
小程序云开发联表数据查询以及云函数中的应用
1、联表查询 (1)lookup联接两个表格 (2)使用match进行条件查询 (3)直接返回学生成绩平均值 (4)只显示teacher和score这两个值 2、在云函数中的应用 (1)在云数据库中添加数据 (2)创建云函数并初始化数据库 (3)编辑云函数入口函数 (4)上传部署云函数
1171 0
小程序云开发联表数据查询以及云函数中的应用
|
11月前
|
JavaScript 搜索推荐 前端开发
Vue SSR 预渲染的广泛应用场景及其优势
【10月更文挑战第23天】Vue SSR 预渲染技术在众多领域都有着广泛的应用价值,可以显著提升网站的性能、用户体验和搜索引擎优化效果。随着技术的不断发展和完善,其应用场景还将不断拓展和深化
207 2
|
10月前
|
机器学习/深度学习 人工智能 计算机视觉
深度学习在医疗影像分析中的应用与挑战
本文探讨了深度学习技术在医疗影像分析领域的应用现状和面临的主要挑战。随着人工智能技术的飞速发展,深度学习已经成为推动医疗影像诊断自动化和智能化的重要力量。文章首先概述了深度学习的基本原理及其在图像识别任务中的优势,随后详细讨论了其在CT、MRI等医疗影像处理中的成功案例,并分析了当前技术面临的数据隐私、模型解释性以及临床验证等方面的挑战。最后,提出了未来研究的方向和可能的解决方案,旨在促进深度学习技术在医疗领域的更广泛应用。
272 0
|
存储 弹性计算 块存储
开发者如何使用块存储EBS
【10月更文挑战第9天】开发者如何使用块存储EBS
422 4
|
11月前
|
人工智能 Kubernetes 云计算
第五届CID大会成功举办,阿里云基础设施加速AI智能产业发展!
2024年10月19日,第五届中国云计算基础架构开发者大会(CID)在北京朗丽兹西山花园酒店成功举办。本次大会汇聚了来自云计算领域的众多精英,不同背景的与会者齐聚一堂,共同探讨云计算技术的最新发展与未来趋势。
|
机器学习/深度学习 编解码 算法
R语言用FNN-LSTM假近邻长短期记忆人工神经网络模型进行时间序列深度学习预测4个案例
R语言用FNN-LSTM假近邻长短期记忆人工神经网络模型进行时间序列深度学习预测4个案例
|
存储 Java 关系型数据库
(透彻)java String.getBytes()编码问题
String.getBytes()的问题String 的getBytes()方法是得到一个字串的字节数组,这是众所周知的。但特别要注意的是,本方法将返回该操作系统默认的编码格式的字节数组。
2012 0