当前位置: 首页 > 科技观察

事件循环机制:JavaScript本来就是单线程的,怎么可能是异步的呢?_0

时间:2023-03-13 00:16:50 科技观察

JavaScript是一种单线程语言。单线程意味着所有的程序路径都按照一定的顺序执行。只有前一个程序执行完,后面的程序才会执行。也就是说,在同一时间,JavaScript只能做一件事。为了协调浏览器产生的各种事件、网络处理、前端渲染等行为,js的事件循环机制,即EventLoop应运而生。JavaScript之所以是单线程的,是因为js最初是作为浏览器的脚本语言设计的。浏览器涉及与用户交互和频繁操作DOM等操作。如果js设计成多线程,就会出现非常复杂的线程同步问题,即使解决了同步问题也会降低浏览器的响应效率,得不偿失。因此,JavaScript被设计成单线程来保证浏览器动作的一致性。事件循环(EventLoop)既然JavaScript是单线程设计的,那么怎么异步呢?这时候就用到了JavaScript的事件循环机制。JavaScript事件循环的示意图如下图所示。如图所示,事件循环就是主线程循环读取任务队列中的任务,直到所有任务执行完毕。在事件循环中,JavaScript使用了栈、堆、队列等数据结构。执行上下文存储在堆栈中。当一个函数被调用时,上下文被创建并存储在执行堆栈中。堆表示用于存储对象的非结构化内存区域。Queue是指一个任务队列,用来存放异步任务。js引擎遇到异步事件后,不会等待事件的返回结果,而是将事件挂起,继续执行执行栈中的其他任务。当异步事件返回结果时,js将异步事件回调函数放入队列中。放入队列的异步事件不会立即被回调。当当前执行栈中的任务全部执行完毕后,空闲的主线程按照队列顺序将第一个事件的回调函数放入执行栈中,并执行该函数的同步代码。如果遇到异步事件,回调函数也会被放入事件队列中……如此重复下去,就会形成一个死循环,这就是它被称为“事件循环(EventLoop)”的原因。宏任务(Microtask)和微任务(Macrotask)js事件循环的基本原理已经说的很清楚了,但是异步任务还是有区别的。上面说了,当JavaScript执行异步任务时,回调函数会被放到js任务队列中。实际上,不同类型的回调函数有不同的执行优先级。不同的优先级分为两类,一类是宏任务(Microtask),一类是微任务(Macrotask)。当回调函数是微任务时,它会被放入微任务队列中,当回调函数是宏任务时,它会被放入宏任务队列中。微任务的优先级高于宏任务。当主线程的任务执行完成后,微任务队列中的第一个回调函数会先执行。当microtask队列为空时,会返回去执行macrotask队列中的回调函数。.常见的微任务包括:promise,常见的宏任务包括setInterval等。因此,事件循环的执行流程图如下: