前言
JavaScript是单线程的脚本语言,意味着它一次只能执行一个任务。然而,现代Web应用常常需要处理异步操作,如网络请求、定时器等,为了让线程不阻塞,Event Loop出现了,它是JavaScript引擎管理异步操作的核心机制。
在Event Loop的学习之前,我们得先弄懂栈与队列这两种数据结构以及JavaScript中的宏任务与微任务。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
- 栈(stack):一种先进后出的数据结构,就像一个桶,最先放的得最后才能拿出来。
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
- 队列(queue):先进先出,就像一个只有一条道的隧道,先进去的车子先出来。
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
EventLoop
概述
EventLoop(事件循环)是编程中管理异步操作和非阻塞IO的一种重要机制,它的目的就是让程序可以在等待某些耗时操作(如网络请求、定时器等)完成的同时,能够执行其他任务,从而避免程序阻塞。换句话说,我在等咖啡的同时EventLoop让我可以边写文章而不是发呆坐在那。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
图解
Event Loop的大概流程:文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
任务在要被执行时会被分为同步和异步任务,同步任务正常执行,如果是异步任务就先放进Event Table中,比如在执行时碰到了一个定时器settimeout,它就会被放入Table中,同时定时器开始计时,当时间结束时它进入Event Queue,在这里面满足先进先出的原则,先来的就会更早来到主线程运行,这样我们的异步任务就不会阻塞我们的同步任务了。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
宏任务与微任务
JavaScript中任务被分为两种,一种叫宏任务,一种叫微任务,它们在Event Loop机制中也扮演着至关重要的角色,与各种异步任务的执行顺序息息相关。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
- 宏任务(Macro Task):
- 整个
script
- 定时器任务,如
setTimeout
、setInterval
。 - 浏览器事件,如
click
、mouseover
。 - 网络请求,如
fetch
、XMLHttpRequest
。 - UI渲染,如重绘。
- 微任务(Micro Task):
Promise
的回调函数Async
/Await
函数MutationObserver
的回调函数process.nextTick
Node.js环境下
执行顺序
先执行整个script这个宏任务,其中会包含各种小的宏任务以及微任务,从上至下,碰到同步任务就执行,碰到宏任务先放进宏任务队列,碰到微任务就放到微任务队列,当script这个宏任务执行到底时,就开始执行微任务队列里面的任务,执行完里面的微任务后去宏任务队列拿一个任务出来,如果这个宏任务里面又有许多微任务那就照样放进微任务队列,等待这个宏任务执行完后再执行微任务队列中的任务。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
总结一下:最开始执行的一定是宏任务,然后这个宏任务中的微任务会先于其中的宏任务执行。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html
说再多都不如来个例子
js
console.log("Start"); // 同步任务
setTimeout(() => { // 宏任务
console.log("In Timeout");
setTimeout(() => { // 宏任务
console.log("timeover");
})
Promise.resolve().then(function() { // 微任务
console.log('promise2');
});
});
Promise.resolve().then(function() { // 微任务
console.log('promise1');
});
console.log("End"); // 同步任务
输出:
解析(从上往下):
- 同步任务先执行,毋容置疑,
Start
直接输出。 - 将第一个settimeout(第2行)放入宏任务队列。
- 把promise(第11行)放入微任务队列。
- 输出
End
。 - 整个script这个宏任务执行完毕,检查微任务队列,发现promise(第11行),执行输出
promise1
。 - 微任务队列清空,执行下一个宏任务settimeout(第2行),同步任务直接输出
In Timeout
。 - 将settimeout(第4行)放入宏任务队列。
- 把promise(第7行)放入微任务队列。
- settimeout(第2行)这个宏任务执行完毕,检查微任务队列,发现promise(第7行),执行输出
promise2
。 - 微任务队列清空,执行下一个宏任务settimeout(第4行),输出
timeover
。
通过例子结合概念理解事半功倍。
结语
想要成为一个好的前端er,Event Loop是核心,它关乎着各项任务的执行顺序,同时也是面试官常考的知识点。不仅要了解这个机制,我们也要正确地分清宏任务与微任务。
评论