本次主要回答两个面试中可能遇到的问题,以及一个关于事件循环的代码题
一、任务有优先级吗?
答案都不用想,当然时否定的
但是消息队列是有优先级的
在W3C中有解释:
1.每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不对类型的任务可以分数与不同的队列。在一次事件循环中,浏览器可以根据实际情况从不同的任务列中取出任务执行;
2.浏览器必须准备号一个微队列,微队列中的任务优先所有其他任务执行。
简单理解就是:浏览器有多少个队列都行,但必须要有一个微队列,并且微队列中的任务优先级最高,其他队列的优先级浏览器可以分配
chrome中部分队列的优先级(不包含所有队列):
延时队列:用于存放定时器到达后的回调任务,优先级【中】;
交互队列:用于存放用户操作产生的事件处理任务,优先级【高】;
微队列:用户存放需要最快执行的任务,优先级【最高】。
二、JS中的计时器能做到准确计时吗?why?
这道题相信大家想都不用想就知道大难是否定的,那么原因则是以下
- 计算器是没有原子钟的,无法做到精确计时(原子钟是目前计时最准确的工具,感兴趣的可以自己搜索一下);
- 操作系统的计时函数本身就有少量偏差,由于JS的计时器最终调用的是操作系统的函数,也就携带了这些偏差;
- 按照W3C的标准,浏览器实现计时器时,如果嵌套层级超过5层,则会带有4毫秒的最少时间,这样在计时时间少于4毫秒时又带来的偏差;
- 受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差。
三、一道简单的代码题
function a() {
console.log(1)
Promise.resolve().then(function() {
console.log(2)
})
}
setTimeout(function() {
console.log(3)
Promise.resolve.then(a)
},0)
Promise.resolve().then(function() {
console.log(4)
})
console.log(5)
大家可以先分析一下,最下面会展示答案
现在开始分析:
当进程开始读取代码时,读到a函数,发现并没有调用;
所有就会继续往下读定时器函数,这时进程会将定时任务交给其他线程去进行计时,计时结束后其他线程会将回调函数放到延时队列中(这是的主线程任务还未结束,所以并不会打印3和调用a函数,所以说回调函数只能在主线程空闲时运行);
随后主线程继续往下读到promise对象,会将其回调函数放到微队列中(注意:微队列优先级最高);
最后主线程打印数字5,打印结束后,主线程第一个任务就结束了。
下面这个图是当前任务结束后其他任务队列中的任务。
从上图也可看出,这是主线程需要从队列中拿去任务,而微队列优先级最高,因此会打印数字4
这时任务队列还有一个,就是:
此时主线程会先打印数字3,随后执行Promise对象,执行结束后又会将回调函数(即函数a)放入微队列中;
此时的任务队列如下:
此时主线程又是先打印数字1,随后又执行Promise对象,执行结束后又又会将回调函数放如微队列中;
此时的任务队列则是:
最后主线程打印数字2,本次是所有任务则结束了
最终答案总结为:
5,4,3,1,2