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)
感谢你阅读本篇文章,希望本篇文章对你有所帮助!
