javaScript中的事件循环(event Loop)
前言
由于javaScript
作为脚本语言,主要用途是与用户互动,以及操作浏览器DOM
。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript
同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?这就导致了javaScript
注定成为一门单线程的脚本语言,没办法多线程执行任务。
什么是event loop(事件循环)?
是指浏览器
或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
查看任务队列中是否存在任务,存在则送到执行栈中执行,反复循环查看并执行,这个过程称之为事件循环(event loop)。
js
的任务分为同步任务
、异步任务
,而异步任务里面又分宏任务
、微任务
。
为啥需要知道event loop?
- 一是要增加自己技术的深度,也就是懂得
JavaScript
的运行机制。 - 二是现在前端领域各种技术层出不穷,掌握底层原理,知道其本质。可以让自己以不变,应万变。
- 三是应对各大互联网公司的面试,懂其原理,题目任其发挥。
案例
看个的经典的代码段,并说明打印的内容
1 | console.log(1) |
上面这段代码输出的正确顺序为:1、3、5、4、2。
原因:setTimeout
为宏任务
;new Promise
的then
/catch
为微任务
/异步任务
;其他的为同步任务
。具体可以看看下面的详细解释,相信你看完过后将会更明白,别人问起将不再吞吐。
宏任务
script
标签中的全部代码、setTimeout
、setInterval
、setImmediate
(浏览器暂时不支持,只有IE10支持,具体可见MDN、I/O
、UI Rendering
。
微任务
Promise
中的then/catch
、async / await
、Process.nextTick
(Node独有)、Object.observe
(废弃)、MutationObserver
(具体使用方式查看这里)
宏任务和微任务执行图表说明
执行栈中会先执行同步任务,同步任务执行完后会执行微任务,微任务执行完后会执行宏任务,当一个宏任务执行后会看执行栈中是否存在同步任务,存在则先执行同步任务,同步任务执行完后会查看是否存在微任务,存在则执行微任务,如果不存在同步任务和微任务则继续宏任务,这个过程是一个循环往复的过程。如果宏任务中存在同步任务和微任务则先执行,并重复刚刚的步骤。
结合上面的案例看,相信你会更加深刻。
同步任务
放入js
主(线程/引擎)中立即执行并原地等待结果的任务。有console
、new Promise
的函数体等。
异步任务
先放入宿主环境(浏览器、node)中,不必原地等待结果的任务,在将来执行,并将执行的回调函数放入主线程,不影响/阻塞主线程继续往下执行的任务。有setTimeout
、Ajax/Fetch
、setInterval
、注册事件回调(如:addEventListener)
、Promise的then/catch
同步任务和异步任务图表说明
当执行栈中的的任务执行完后会清除一次执行栈,并重新从任务队列中拿取任务并执行(异步任务)。
创建完同步任务后会直接放进执行栈并原地等待执行结果;
异步任务创建时会先放进宿主环境,带时机成熟(比如定时器的时间到了)会将异步任务回调放入任务队列中,然后执行栈会根据任务队列中的任务进行执行。
结合上面的案例看,相信你会更加深刻。
我们将事件查找并执行的这样一个循环过程称之为事件循环
,也叫 event loop
。
总结
- js 是单线程的,防止代码执行过程中的阻塞,我们把任务分为了:同步任务和异步任务
- 同步任务将会交给js引擎执行,异步任务将交给宿主环境执行
- 同步任务将放入执行栈立即执行并原地等待结果,异步任务会待时机成熟时推入任务队列排队执行
- 执行栈执行完毕时,会清空执行栈并查看任务队列中是否存在任务,存在则送到执行栈中执行,反复循环查看并执行,这个过程称之为事件循环(event loop)
感谢你阅读本篇文章,希望本篇文章对你有所帮助!