js是单线程的,单线程就是说在执行js代码的时候一步一步的往下执行,而js代码分为同步代码和异步代码(比如axios请求,setTimeOut等),当一步一步往下执行的时候,单线程就以为着我们需要等待这些异步代码执行完毕才能进行下一步的执行,这样就显得非常的低效率。那怎样才能解决这个问题呢?
浏览器的事件循环机制就解决了这个问题,那它是怎样进行循环的呢?
首先我们要知道,js分为同步任务和异步任务,异步任务又分为了宏任务和微任务,如下:
同步任务:
- 变量赋值,如:var m = 1;
- 逻辑运算,如:num = a + b;
- 函数的调用,如:Fn();
- new Promise()时传入的参数;
异步任务:
- 微任务:promise.then、MutationObserver(H5新增的特性);
- 宏任务:setTimeout、setInterval等
接下来就开始了浏览器的事件循环机制:
第一步:从<script>开始,到</script>结束,执行里面的所有代码;
第二步:执行script里面的代码时,遇到同步代码就立即执行,遇到异步的任务就将异步的任务就交给对应的模块处理(事件交给事件处理线程,ajax交给异步HTTP请求线程),当异步任务达到触发的条件后就将异步的的回调推入任务队列(宏任务推入宏任务队列,微任务推入微任务队列);
第三步:当前两步执行完毕之后,即同步代码执行完毕。这时候就要读取并且执行微任务队列中的所有的微任务;
第四步:第三步完成后,开始执行宏任务队列中的宏任务,每执行完一个宏任务,就要去检查微任务队列中是否有新增的微任务,如果存在的话,则重复步骤三;如果不存在的话,就继续执行下一个宏任务,直到宏任务执行完毕。
这就是浏览器的事件循环机制。
实践一波~~~
下列代码的打印顺序:
1、执行所有的同步代码:
首先是函数的调用:打印 'printNumber'
其次是执行new Promise传入的参数:打印‘new promise’;
2、执行微任务队列中的所有微任务:
首先是.then: 打印‘promise resolve’
3、执行宏任务队列中的宏任务的回调:打印‘setTimeout 0’;‘setTimeout 1000’;