为何会写这篇博文呢?
前段时间,和头条的小伙伴聊天问头条面试前端会问哪些问题,他称若是是他面试的话,event-loop确定是要问的。那天聊了蛮多,event-loop算是给我留下了很深的印象,缘由很简单,由于以前我从未深刻了解过,若是是面试的时候,我遇到了这个问题,估计回答得确定不如人意。javascript
所以,最近我阅读了一些相关的文章,并细细梳理了一番,输出了本篇博文,但愿能帮助你们搞懂浏览器的event-loop。后续会补充node中的event-loop。html
JavaScript的运行机制:
(1)全部同步任务都在主线程上执行,造成一个执行栈(execution context stack)。前端
(2)主线程以外,还存在"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。java
(3)一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,因而结束等待状态,进入执行栈,开始执行。node
(4)主线程不断重复上面的第三步git
归纳便是: 调用栈中的同步任务都执行完毕,栈内被清空了,就表明主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操做github
一个事件循环中有一个或者是多个任务队列
JavaScript中有两种异步任务:
主线程从"任务队列"中读取执行事件,这个过程是循环不断的,这个机制被称为事件循环。此机制具体以下:主线程会不断从任务队列中按顺序取任务执行,每执行完一个任务都会检查microtask队列是否为空(执行完一个任务的具体标志是函数执行栈为空),若是不为空则会一次性执行完全部microtask。而后再进入下一个循环去任务队列中取下一个任务执行。面试
详细说明:
执行进入microtask检查的的具体步骤以下:shell
须要注意的是:当前执行栈执行完毕时会马上先处理全部微任务队列中的事件,而后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务以前执行。segmentfault
图示:
先看一个简单的示例:
setTimeout(()=>{ console.log("setTimeout1"); Promise.resolve().then(data => { console.log(222); }); }); setTimeout(()=>{ console.log("setTimeout2"); }); Promise.resolve().then(data=>{ console.log(111); });
思考一下, 运行结果是什么?
运行结果为:
111 setTimeout1 222 setTimeout2
咱们来看一下为何?
咱们来详细说明一下, JS引擎是如何执行这段代码的:
再思考一下下面代码的执行顺序:
console.log('script start'); setTimeout(function () { console.log('setTimeout---0'); }, 0); setTimeout(function () { console.log('setTimeout---200'); setTimeout(function () { console.log('inner-setTimeout---0'); }); Promise.resolve().then(function () { console.log('promise5'); }); }, 200); Promise.resolve().then(function () { console.log('promise1'); }).then(function () { console.log('promise2'); }); Promise.resolve().then(function () { console.log('promise3'); }); console.log('script end');
思考一下,运行结果是什么?
运行结果为:
script start script end promise1 promise3 promise2 setTimeout---0 setTimeout---200 promise5 inner-setTimeout---0
那么为何?
咱们来详细说明一下,JS引擎是如何执行这段代码的:
由于 JavaScript 是单线程的。单线程就意味着,全部任务须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就不得不一直等着。为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking)等,用户代理(user agent)必须使用事件循环(event loops)。
谢谢您花费宝贵的时间阅读本文,若是本文给了您一点帮助或者是启发,那么不要吝啬你的赞和Star哈,您的确定是我前进的最大动力。https://github.com/YvetteLau/...
推荐关注本人公众号: