关于setTimeout的延时参数

各位大佬,小弟请问个问题:
以下代码为什么输出结果是1,4,3,2,而不是1,4,2,3
js主线程从上至下执行时,碰到异步代码,会将其插入到任务队列,任务队列里应该是1000的在0的前面,还是说setTimeout第二个参数就是延时多长时间将其插入到任务队列?

console.log(1);
setTimeout(function () {
    console.log(2);
}, 1000);
setTimeout(function () {
    console.log(3);
}, 0);
console.log(4);

结果:
图片描述

阅读 5.2k
9 个回答

题主似乎对js的任务队列有误解,就是因为js是单线程的,才有的这个任务队列机制,但任务队列并不是单线程的,可以多任务同步执行 [由浏览器实现]
所以你的2个setTimeout基本是同时委托浏览器异步执行计时操作,浏览器根据你设定的时间调用回调函数,肯定是设置为0的那个先触发了

console.log(1);//最先执行
setTimeout(function () {
    console.log(2);//这个没什么好说的,1秒后执行,最后一个
}, 1000);
setTimeout(function () {
    console.log(3);//定时器有延时,虽然设置了0,代表0秒后就执行,但是实际是有一定延时的,接近0而已,相当于异步,所以要等同步执行的执行完才轮到它,所以第三
}, 0);
console.log(4);//第二执行

我理解的第二个参数是加入异步队列后多长时间再执行

因为输出3的延迟时间是0,输入2的延迟时间是1000啊!!!!!
setTimeout(code,millisec)

参数 描述
code 必需。要调用的函数后要执行的 JavaScript 代码串。
millisec 必需。在执行代码前需等待的毫秒数。

第2个延迟了1秒当然要比第3个延迟0秒更晚执行

可以看一下阮一峰前辈的关于定时器运行机制的讲解,也许能帮你解惑http://javascript.ruanyifeng....

另外一点,定时器通过单独线程来计时并触发定时(计时完毕后,添加到事件循环队列中,等待JS引擎空闲后执行),并非用js引擎计数的

setTimeout(function () {
    console.log(2);
}, 1000);
setTimeout(function () {
    console.log(3);
}, 500ms);
// 打印结果是 3  2

你的理解没有问题:js主线程从上至下执行时,碰到异步代码,会将其插入到任务队列,任务队列里应该是1000的在0的前面。等执行完主线程的任务,再执行任务队列的任务但是setTimeout()方法设置的定时器。
但是有一点你理解错了,看上面的代码,不是说先等待上面的setTimeout设定的1000ms输出2,再等待下面的setTimeout设定的500ms输出3,而是先等待500ms,下面的setTimeout设定的时间到了,输出3,再过去500ms(1000ms - 500ms),上面的setTimeout设定的时间到了,输出2。
所以总共等待的时间是1000ms,而不是你理解的1000ms + 500ms

1000 的确排在 0 前面,但 console.log(4) 周期完后检查队列发现 1000 的时间还没到就被跳过了。

setTimeout(fn, delay)第二个参数默认是可以缺省的,如果不传,浏览器会自动添加到浏览器的任务队列中,等下一轮事件对垒开始时执行,延时时间不确定;但是如果传递了确定参数,也不代表这个函数在确定的时间后执行(各个浏览器的时间都不一样)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题