【各大厂常见面试题4】--事件循环

704 阅读4分钟

【各大厂常见面试题4】--事件循环

1.浏览器Event Loop

1.1 浏览器Event Loop 定义

浏览器环境下,js单线程机制使得js执行过程中永远只能同时执行一个任务,每次任务的执行主线
程会优先执行同步任务,每次执行完成所有同步任务后对microtask 做检查看是否为空
,如果为空,则判断是否需要进行渲染页面,如果不需要,再进行下次循环,
如microtask队列不为空则先执行完所有的microtask,再执行下一次宏任务。知道执行完成所有的任务队列。

1.2 浏览器Event Loop 执行顺序

执行同步代码
执行完所有同步代码后且执行栈为空,判断是否有微任务需要执行
执行所有微任务且微任务队列为空
是否有必要渲染页面
执行一个宏任务

image.png

1.3 宏任务和微任务

宏任务

setTimeout
setImmediate
setIntarval
requestAnimationFrame
I/O
UI rendering

微任务

process.nextTick
Promise.then
Object.observe
MutationObserver

2.node事件循环

2.1 node事件循环定义

Node.js 在主线程里维护了一个事件队列,当接到请求后,就将该请求作为一个事件放入这个队列中,然后继续
接收其他请求。当主线程空闲时(没有请求接入时),就开始循环事件队列,检查队列中是否有要处理的事件,这时
要分两种情况:如果是非 I/O 任务,就亲自处理,并通过回调函数返回到上层调用;如果是 I/O 任务,就从线
程池中拿出一个线程来处理这个事件,并指定回调函数,然后继续循环队列中的其他事件。当线程中的 I/O 任务
完成以后,就执行指定的回调函数,并把这个完成的事件放到事件队列的尾部等待事件循环,当主线程再次循环
到该事件时,就直接处理并返回给上层调用。 

2.2 Node.js事件循环四层

Node.js事件循环四层被分为了四层,分别是 应用层、V8引擎层、Node API层 和 LIBUV层。
应用层:   即 JavaScript 交互层,常见的就是 Node.js 的模块,比如 http,fs
V8引擎层:  即利用 V8 引擎来解析JavaScript 语法,进而和下层 API 交互
NodeAPI层:  为上层模块提供系统调用,一般是由 C 语言来实现,和操作系统进行交互 。
LIBUV层: 是跨平台的底层封装,实现了 事件循环、文件操作等,是 Node.js 实现异步的核心 。
总结:无论是 Linux 平台还是 Windows 平台,Node.js 内部都是通过 线程池 来完成异步 I/O 操作的,而 
LIBUV 针对不同平台的差异性实现了统一调用。因此,Node.js 的单线程仅仅是指 
JavaScript 运行在单线程中,而并非 Node.js 是单线程。

2.3 node的Event Loop 执行顺序

timers:执行setTimeout() 和 setInterval()中到期的callback。
I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的这一阶段执行
idle, prepare:队列的移动,仅内部使用
poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段
check:执行setImmediate的callback
close callbacks:执行close事件的callback,例如socket.on("close",func)

image.png

3. 浏览器事件循环示例

console.log(1);      
setTimeout(function() {   
    console.log(2);  
})       
var promise = new Promise(function(resolve, reject) {  
    console.log(3);  
    resolve();   
})   
promise.then(function() {  
    console.log(4);   
})    
console.log(5);

4.延伸面试题

4.1 题目描述:

如有以下代码,如何改造让其按顺序输出1 2 ?

var promise = new Promise(function(resolve, reject) {  
    console.log(0);  
    resolve();  
    console.log("*****");  
})  
promise.then(function() {
 
}).catch(function() {
    console.log(1);
}).then(function() {
  
}).catch(function() {
    console.log(2);
})

4.2 思路分析:

 利用Promise.reject(reason)方法也会返回一个新的 Promise 实例,
 该实例的状态为rejected。catch方法默认会捕获并将报错信息进行输出。

4.3 AC 代码:

 var promise = new Promise(function(resolve, reject) {  
    console.log(0);  
    resolve();  
    console.log("*****");  
})  
promise.then(function() {
    reject('失败了')
}).catch(function() {
    console.log(1);
}).then(function() {
    reject('失败了')
}).catch(function() {
    console.log(2);
})

// 输出: 0    *****   1   2  

最后 附其他面试题
【各大厂常见面试题3】--http和https系列
【各大厂常见面试题2】--函数
【各大厂常见面试题1】--变量

读后有收获可以微信请作者喝咖啡,有疑问请加微信讨论

image.png image.png