美丽的神话 发表于 2024-9-14 18:02:57

JS【详解】setTimeout 延时(含扫除 setTimeout,计时开始时间,0 秒延时解

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 时,因其为宏任务,会将其放入 Web APIs 中,并开始计时
   0 秒延时并不代表立即实行!

https://i-blog.csdnimg.cn/blog_migrate/07e672cbaf4b956dc647f70a74ff775c.png#pic_center
如上图可见,属于 宏任务的 setTimeout 需等候同步任务、微任务、DOM渲染完成后,通过事件轮询触发实行
print("同步任务执行开始");

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

print("同步任务执行结束");
实行效果
同步任务执行开始————当前时间:2024年5月29日14时42分29秒
同步任务执行结束————当前时间:2024年5月29日14时42分29秒
setTimeout延时0秒执行————当前时间:2024年5月29日14时42分29秒
   setTimeout 的回调函数,详细什么时候开始实行?

存在复杂异步逻辑时,很难精准预判 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秒
   多个 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.style.display = "none";
      imgArr.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);
}
解析:立即实行函数的原理和 let 类似,也是形成了局部作用域,实现了预期效果。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: JS【详解】setTimeout 延时(含扫除 setTimeout,计时开始时间,0 秒延时解