JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)

setTimeout 简介

setTimeout 是一个 js 内置的函数,用于延时执行代码

  • 参数1:回调函数,延迟一段时间后执行的代码
  • 参数2:延迟的时间,单位是毫秒。(默认为 0 毫秒)
  • 返回值:计时器的ID,是一个整数(例子中的 timer)。
const timer = setTimeout(function() {
    console.log(1); // 3 秒后,打印 1
}, 3000);

清除 setTimeout

clearTimeout(timer); // timer 为计时器的ID

setTimeout 什么时候开始计时?

首先, setTimeout 属于 js 异步任务中的宏任务

如上图可见,宏任务需等待同步任务、微任务、DOM渲染完成后,通过事件轮询触发执行,所以存在复杂异步逻辑时,很难精准预判 setTimeout 的开始计时时间。

逻辑简单的,比较好分析,如

function test() {
  print("开始");

  setTimeout(() => {
    print("执行 setTimeout");
  }, 1000);

  print("结束");
}
  • setTimeout 从打印 “结束” 后开始计时
  • 从计时开始 1 秒后,打印 “ 执行 setTimeout ”

下方代码可以展示得更清晰:

function print(info) {
  let dt = new Date();
  var y = dt.getFullYear();
  var mt = dt.getMonth() + 1;
  var day = dt.getDate();
  var h = dt.getHours(); //获取时
  var m = dt.getMinutes(); //获取分
  var s = dt.getSeconds(); //获取秒
  let str =
    "当前时间:" +
    y +
    "年" +
    mt +
    "月" +
    day +
    "日" +
    h +
    "时" +
    m +
    "分" +
    s +
    "秒";

  console.log(info + "————" + str);
}

function sleep(delay) {
  var start = new Date().getTime();
  while (new Date().getTime() - start < delay) {
    continue;
  }
  print("sleep 执行完毕");
}

function test() {
  print("开始");

  sleep(1000);

  setTimeout(() => {
    print("执行 setTimeout");
  }, 1000);

  print("结束");
}

test();

执行结果

开始————当前时间:2024年5月29日14时11分23秒
sleep 执行完毕————当前时间:2024年5月29日14时11分24秒
结束————当前时间:2024年5月29日14时11分24秒
执行 setTimeout————当前时间:2024年5月29日14时11分25秒

0 秒延时并不代表立即执行!

print("同步任务执行开始");

setTimeout(function () {
  print("setTimeout延时0秒执行");
}, 0);

print("同步任务执行结束");

一旦添加了 setTimeout ,便是一个异步宏任务,需等同步任务、异步微任务、DOM渲染完成后,通过事件轮询触发执行。

多个 setTimeout 的执行顺序 ?

function test() {
  console.time("本段代码总耗时");

  print("同步任务执行开始");

  setTimeout(function () {
    print("setTimeout延时3秒执行");
    console.timeEnd("本段代码总耗时");
  }, 3000);

  setTimeout(function () {
    print("第1个setTimeout延时2秒执行");
  }, 2000);

  setTimeout(function () {
    print("第2个setTimeout延时2秒执行");
  }, 2000);

  print("同步任务执行结束");
}

test();

执行结果

同步任务执行开始————当前时间:2024年5月29日14时21分20秒
同步任务执行结束————当前时间:2024年5月29日14时21分20秒
第1个setTimeout延时2秒执行————当前时间:2024年5月29日14时21分22秒
第2个setTimeout延时2秒执行————当前时间:2024年5月29日14时21分22秒
setTimeout延时3秒执行————当前时间:2024年5月29日14时21分23秒
本段代码总耗时: 3.005s
  • 所有 setTimeout 的开始计时时间几乎相同
  • 延时相同的 setTimeout ,会按 setTimeout 的出现的先后顺序执行
  • 延时不同的 setTimeout ,延时越久的 setTimeout 越晚执行

setTimeout 的应用场景

5秒后关闭网页两侧的广告栏

window.onload = function () {
    //获取相关元素
    var imgArr = document.getElementsByTagName("img");
    //设置定时器:5秒后关闭两侧的广告栏
    setTimeout(fn,5000);
    function fn(){
        imgArr[0].style.display = "none";
        imgArr[1].style.display = "none";
    }
}

setTimeout 的网红面试题

下方代码的执行结果是?

for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  });
}

答案

10
10
10
10
10
10
10
10
10
10

解析 :


setTimeout 是异步宏任务,for 循环是同步任务,for 循环先执行,依次在Web APIs 中添加了10个setTimeout,待 for 循环完毕,i 的值已变为 10 ,此时才开始事件轮询,setTimeout 依次开始计时,因延时为0秒,最终效果为 for 循环完毕后,立马一次执行 10 次 setTimeout 的回调,即依次打印 10 个 10

延展提问:怎样改动实现打印 0 到 9 ?

答案1:将 var 改成 let

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  });
}

解析:let 声明的变量具有局部作用域, var 声明的变量是全局作用域,改用 let 后,执行 setTimeout 内的回调函数时,取到的 i 值为 setTimeout 被放入 Web APIs 时的值,即 for 循环时 i 的值。


答案2:改用立即执行函数包裹

for (var i = 0; i < 10; i++) {
  (function (i) {
    setTimeout(() => {
      console.log(i);
    });
  })(i);
}


目录
相关文章
|
3月前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
3月前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
128 59
|
2月前
|
JSON JavaScript 前端开发
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
本文介绍了JSONP的工作原理及其在解决跨域请求中的应用。首先解释了同源策略的概念,然后通过多个示例详细阐述了JSONP如何通过动态解释服务端返回的JavaScript脚本来实现跨域数据交互。文章还探讨了使用jQuery的`$.ajax`方法封装JSONP请求的方式,并提供了具体的代码示例。最后,通过一个更复杂的示例展示了如何处理JSON格式的响应数据。
41 2
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
|
2月前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
67 0
|
2月前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
50 0
|
3月前
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
42 0
|
3月前
|
Web App开发 存储 前端开发
前端开发必备:requestAnimationFrame、setInterval、setTimeout——功能解析与优劣对比
前端开发必备:requestAnimationFrame、setInterval、setTimeout——功能解析与优劣对比
196 0
|
3月前
|
JavaScript API
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
179 0
|
3月前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
62 0
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
87 2

热门文章

最新文章

推荐镜像

更多