上周五,一个朋友发给我一道面试题,代码以下:html
console.log(1); setTimeout(console.log(2), 0); Promise.resolve().then(res => { console.log(3); }).then(res=>{ console.log(4); }) console.log(5);
朋友说在控制台跑完的结果是依次打印出 1 2 5 3 4,可是不清楚为何,但愿我帮他分析下。面试
额,我以为setTimeout里的那个打印,是在下次事件循环时才会执行的,因此打印结果应该是 1 5 2 3 4 。。。。。浏览器
然而,结果并不是如此。说明我还处于朦胧状态啊,因而乎,开始去网上找博客。多线程
如下内容均是在博客中看到的内容,加上一点点本身的理解,至因而否客观正确,这个另说哈,时间会检验一切的。dom
主线程从"任务队列"中读取事件,这个过程是循环不断的,因此整个的这种运行机制又称为Event Loop(事件循环)。异步
从上图看到(下面这段也是抄的😁):函数
除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与"任务队列"有关的方法:process.nextTick和setImmediate。 process.nextTick方法能够在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")以前----触发回调函数。也就是说,它指定的任务老是发生在全部异步任务以前。 setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务老是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。
其实还有不少东西没有好好整理出来,下面只是大概记录下,详细的内容,查看下面的博文连接哈oop
若是在原来的setTimeout console外面包了function。执行结果是1 5 3 4 2。post
首先,1 5 是同步任务,因此主线程中执行,setTimeout属于宏任务,添加到任务队列中,Promise是异步的,属于微任务,在同步任务执行完毕后执行,而且它也是链式的,因此它的回调函数会依次被添加到微任务中,微任务会在任务队列中的每个task执行完后执行线程
总之,setTimeout(fn,0)的含义是,指定某个任务在主线程最先可得的空闲时间执行,也就是说,尽量早得执行。它在"任务队列"的尾部添加一个事件,所以要等到同步任务和"任务队列"现有的事件都处理完,才会获得执行。
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,若是低于这个值,就会自动增长。在此以前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变更(尤为是涉及页面从新渲染的部分),一般不会当即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。
须要注意的是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等好久,因此并无办法保证,回调函数必定会在setTimeout()指定的时间执行。
But,还有个问题没搞明白:
setTimeout( function(){ console.log(2) }, 0 );
和
setTimeout( console.log(2), 0 );
有啥子区别呢?执行结果不同呢