最近几天,面试了几个应聘的。有一道面试题,答案真是千奇百怪。就是这么一道题:
setTimeout(() => {
console.log("setTimeout");
});
let p1 =new Promise((resolve) => {
console.log("Promise1");
resolve("Promise2");
});
p1.then((res) => {
console.log(res);
});
console.log("over");
当然有的答对的可能是见过这么一道相似的类似题目,我们来简单聊一聊这是一道什么样的题。
接触JS的肯定都知道,JS是单线程的。而单线程就意味着所有的任务都要进行排队,依次执行,这就是任务队列。但是会有那样的任务执行起来很耗时间,而我们还有很多没有利用的CPU空间。所以就产生了:JS中任务是有同步(synchronous)和异步(asynchronous)的分别的。同步就是顺次执行的那一种,而异步就是需要等待的那一种。同步和异步的执行路线是不同的:同步会进入主线程顺次执行。只有前一个执行结束才会执行下一个;而异步会进入一个等待的队列,可以理解为等待中的任务队列(任务队列就是一个先进先出的队列结构,主线程的执行队列的读取是自动的)。在这里异步任务会在Event Table中注册相应的回调函数。当指定的步骤完成了,Event Table会将注册了的回调函数推送到Event Queue,在Event Queue这里进行等待上场。当主线程内的任务执行完毕为空之后,就会到Event Queue读取相应的函数,进入主线程执行。这个过程不断重复构成Event Loop。
这个就是同步与异步的简单过程。
但是,会有一个疑问,向上面的那道题目中的SetTimeout和promise都是异步任务那他俩的执行属性呢?难道是顺次,这个还真不一定。
JS的异步也是有一个机制的,就是会分为宏任务和微任务。宏任务和微任务会放到不同的event queue中,先将所有的宏任务放到一个event queue,再将微任务放到一个event queue中。执行完宏任务之后,就会先从微任务中取这个回调函数执行。
那么什么是宏任务呢,一般就是setTimeout、setInterval、script、I/O
微任务就是,Promise\process.nextTick
让我们回到那道题,首先会执行script下的宏任务,解析,遇到setTimeout,判断它是一个宏任务类型,将其放到一个宏任务的queue中;遇到Promise,开始执行,打印 Promise1 ;往下遇到then,判断是个微任务,放到微任务的队列中,等待执行;继续解析,打印 over 。查证本轮次的宏任务都执行完毕了,开始执行本轮的微任务,发现有一个then的回调函数,打印 Promise2 , 到这里微任务页执行完毕了,这样本轮次的Loop全部执行完毕,开始下一轮次的Loop。发现宏任务的队列有一个setTimeout的回调函数,打印 setTimeout 。
网友评论