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

简介: 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);
}


目录
相关文章
|
4月前
|
JavaScript 前端开发 IDE
TypeScript vs. JavaScript:技术对比与核心差异解析
TypeScript 作为 JavaScript 的超集,通过静态类型系统、编译时错误检测和强大的工具链支持,显著提升代码质量与可维护性,尤其适用于中大型项目和团队协作。相较之下,JavaScript 更灵活,适合快速原型开发。本文从类型系统、错误检测、工具支持等多维度对比两者差异,并提供技术选型建议,助力开发者合理选择。
967 1
|
4月前
|
JavaScript 前端开发 开发者
Nest.js控制器深度解析:路由与请求处理的高级特性
以上就是对 NestJS 控制层高级特性深度解析:从基本概念到异步支持再到更复杂场景下拦截其与管道等功能性组件运用都有所涉及,希望能够帮助开发者更好地理解和运用 NestJS 进行高效开发工作。
383 15
|
4月前
|
存储 JavaScript 前端开发
JavaScript 语法全面解析
JavaScript 语法体系丰富且不断更新,从基础的变量声明、数据类型,到复杂的函数、对象、异步语法,每个知识点都需要开发者深入理解并灵活运用。本文梳理的 JS 语法核心内容,可为开发者提供系统的学习框架,后续还需通过大量实践(如编写交互组件、实现业务逻辑)巩固知识,逐步提升 JS 编程能力,应对前端开发中的各类挑战。
|
7月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
324 19
|
8月前
|
JSON 前端开发 Serverless
Mock.js 语法结构全解析
Mock.js 的语法规范介绍,从数据模板定义规范和数据占位符定义规范俩部分介绍, 让你更好的使用 Mock.js 来模拟数据并提高开发效率。
|
10月前
|
机器学习/深度学习 人工智能 JSON
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
Resume Matcher 是一款开源AI简历优化工具,通过解析简历和职位描述,提取关键词并计算文本相似性,帮助求职者优化简历内容,提升通过自动化筛选系统(ATS)的概率,增加面试机会。
1301 18
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
|
10月前
|
数据采集 前端开发 JavaScript
金融数据分析:解析JavaScript渲染的隐藏表格
本文详解了如何使用Python与Selenium结合代理IP技术,从金融网站(如东方财富网)抓取由JavaScript渲染的隐藏表格数据。内容涵盖环境搭建、代理配置、模拟用户行为、数据解析与分析等关键步骤。通过设置Cookie和User-Agent,突破反爬机制;借助Selenium等待页面渲染,精准定位动态数据。同时,提供了常见错误解决方案及延伸练习,帮助读者掌握金融数据采集的核心技能,为投资决策提供支持。注意规避动态加载、代理验证及元素定位等潜在陷阱,确保数据抓取高效稳定。
330 17
|
10月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
存储 JavaScript 前端开发
全网最全情景,深入浅出解析JavaScript数组去重:数值与引用类型的全面攻略
如果是基础类型数组,优先选择 Set。 对于引用类型数组,根据需求选择 Map 或 JSON.stringify()。 其余情况根据实际需求进行混合调用,就能更好的实现数组去重。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多
  • DNS