1. 最基础的误解:setTimeout(fn, 1000) 不等于“1秒后准时执行”
别被参数名字骗了。setTimeout 的真实意思是:“至少等1000毫秒后,把这个函数 fn 放进一个待办事项列表(任务队列)里排队。等当前手头所有活儿都干完了,再轮到它执行。”
看个简单例子就懂了:
console.log("开始");
setTimeout(() => { console.log("定时器到了!"); }, 0); // 延迟设为0
console.log("结束");
输出顺序是:
开始
结束
定时器到了!
为什么 0 秒延迟也没立刻执行?因为 setTimeout 的回调函数(就是那个打印“定时器到了!”的函数)被放进队列后,必须等到当前正在跑的代码(就是打印“开始”和“结束”的那段)全部执行完毕,主线程闲下来了,才会去队列里把它拿出来执行。即使延迟是0,也要排队。
2. 主线程忙不过来,定时器就得一直等(延迟漂移)
JavaScript 在一个线程里干活(单线程)。如果这个线程被其他事情卡住了,setTimeout 设定的时间到了也没用,回调函数只能在队列里干等着。
看这个例子:
console.log("开始");
setTimeout(() => { console.log("Timeout!"); }, 1000);