一、为什么会有event loop?
js的任务分为同步和异步两种:
1、同步任务是直接放在主线程上排队依次执行;
2、异步任务会放在任务队列中,若有多个异步任务则需要在任务队列中排队等待,
任务队列类似于缓冲区,任务下一步会被移到调用栈然后主线程执行调用栈的任务。
调用栈:是一个栈结构,函数调用会形成一个栈帧,帧中包含了当前执行函数的参数和局部变量等上下文信息,
函数执行完成后,它的执行上下文会从栈中弹出。
js是单线程的,单线程是指js引擎中解析和执行js代码的线程只有一个,每次只做一件事,
而ajax请求中,主线程在等待响应的过程中回去做其他的事情,浏览器先在事件表注册ajax的回调函数,
响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,这种方式是异步的。
所以,检查调用栈是否为空以及将某个任务添加到调用栈中的过程就是event loop,这就是js实现异步的核心。
二、浏览器中的Event Loop
1、micro-task和macro-task
浏览器端事件循环中的异步队列有两种:micro(微任务队列)、macro(宏任务队列);
常见的宏任务:setTimeout、setInterval、script(整体代码)、I/O操作、UI渲染等;
常见的微任务:new Promise().then()、MutationObserve、process.nextTick()等;
2、事件循环的过程
检查宏任务队列是否为空,非空则执行宏任务队列中的一个任务,
为空则继续检查微任务队列是否为空,
非空则取出微任务队列中的任务执行,执行完成继续检查微任务对列,微任务队列为空则执行视图更新。
三、node中的event loop
1、node中的事件循环和浏览器中的是完全不相同的东西。nodejs采用v8作为js的解析引擎, I/O处理方面使用了自己设计的libuv,libuv是一个基于事件驱动的跨平台抽象层,封装了不同操作系统的底层特性,对外提供统一的api,事件循环机制也是它里面实现的。
2、node的运行机制如下:
1、v8引擎解析js脚本;
2、解析后的代码调用node api;
3、libuv库负责node API的执行。它将不同的任务分给不同的线程,形成一个事件循环,
以异步的方式将任务的执行结果返回給v8引擎;
4、v8引擎再将结果返回給用户。
3、六大阶段
libuv引擎中的事件循环分为6个阶段,它们会按照顺序反复运行。
1、timers阶段:这个阶段执行 timer(setTimeout、setInterval)的回调;
2、I/O callbacks阶段:处理一些上一轮循环中的少数未执行的 I/O 回调;
3、idle, prepare 阶段:仅 node 内部使用
4、poll 阶段:获取新的 I/O 事件, 适当的条件下 node 将阻塞在这里
5、check 阶段:执行 setImmediate() 的回调
6、 callbacks 阶段:执行 socket 的 close 事件回调