事件循环(搞懂异步各任务的执行顺序)

在说我们的事件循环之前我们需要先知道这两个概念:
1、什么是同步和异步
2、JS异步是怎么实现的

首先同步和异步。其实这个很很好理解,同步其实就是代码按照我们的编写顺序执行,那么异步呢其实就是代码的执行顺序可能会和我们的编写顺序不一样

JS异步是怎么实现的?
我们都知道JS是单线程执行语言,其实单线程指的是JS的主运行线程只有一个,并不是说整个运行环境都是单线程的。JS的运行环境主要是浏览器,那么我们的浏览器内核(比如chrome)不仅仅是多线程的还是多进程的
所以JS异步的实现靠的就是浏览器的多线程,当他遇到异步API时,就将这个任务交给对应的线程,当这个异步API满足回调条件时,对应的线程又通过事件触发线程将这个事件放入任务队列,然后主线程从任务队列取出事件继续执行。这个流程我们多次提到了任务队列,这其实就是Event Loop

其实这个event loop就是我们要讲的事件循环
我们先理解一下下面这个图
在这里插入图片描述
那么什么是宏任务和微任务呢
规范中规定,task分为两大类, 分别是 Macro Task (宏任务)和 Micro Task(微任务), 并且每个宏任务结束后, 都要清空所有的微任务,这里的 Macro Task也是我们常说的 task ,有些文章并没有对其做区分

宏任务主要包含:script( 整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)
微任务主要包含:Promise、MutaionObserver、process.nextTick(Node.js 环境)
setTimeout/Promise 等API便是任务源,而进入任务队列的是由他们指定的具体执行任务。来自不同任务源的任务会进入到不同的任务队列。其中 setTimeout 与 setInterval 是同源的。

那么我们的代码在运行的时候,是先执行一个宏任务再清空微任务,这样执行,那么其实任务中也有执行的优先级,比如说这里process.nextTick这个的优先级就是最高的(相当于微任务而言),然后setImmediate的优先级也会比
setTimeout(fn,0)高,但是具体为什么这个就需要看在node环境下的运行机制,我们稍后述说。

举几个例子吧!

 console.log('script start');
        setTimeout(function() {
          console.log('setTimeout');
        }, 0);
        
        Promise.resolve().then(function() {
          console.log('promise1');
        }).then(function() {
          console.log('promise2');
        });
        console.log('script end');

很明显这个没有转弯大家就可以直接写出答案

start end promise1  promise2 setTimeout 

再来一个在node环境下运行的例子

function timer() {
    setTimeout(()=>{
        console.log(1);
    },0)
    setImmediate(()=>{
        console.log(2);
    })
    console.log(3);
    process.nextTick(()=>{
        console.log(4);
    })
}

那么就像我们刚刚说的那样,这次的输出结果是
在这里插入图片描述
但是在目前我们只是掌握了一些基本的,关于node,其实他和浏览器对于事件循环还是有一定的区别的,nodejs中的宏任务被分成了几种不同的阶段,两个定时器属于timers阶段,setImmediate属于check阶段,socket的关闭事件属于close callbacks阶段,其他所有的宏任务都属于poll阶段,除此之外,只要执行到前面说的某个阶段,那么会执行完该阶段所有的任务,这一点和浏览器不一样,浏览器是每次取一个宏任务出来执行,执行完后就跑去检查微任务队列了,但是nodejs是来都来了,一次全部执行完该阶段的任务好了,那么process.nextTick和微任务在什么阶段执行呢,在前面说的每个阶段的后面都会执行,但是process.nextTick会优先于微任务,一图胜千言:
在这里插入图片描述
接下来再来看这题:
在这里插入图片描述
通过我们刚刚说的,首先是js的整体执行,输出1
接下来遇到setTimeout就把他放进timer队列
然后遇到promise先输入同步的7
把then放进微队列
遇到nextick放进nextTick对咧
接着又遇到setTimeOut放进timer队列
到这里第一遍走完接着输出nexttick队列和微队列
所以输出6和8
然后会从上面那个图的阶段依次查找,从check阶段一直往上找,找到timer才有,于是执行第一个timer
输出2 然后遇到nextTick放进nextTick队列然后输出同步4
把then放进微队列
然后执行第二个timer也是这样
先输出9 然后遇到nextTick放进nextTick队列然后输出同步11
把then放进微队列
最后先清空nextTick队列再清空微队列
就是3 10 5 12
所以输出的顺序为 1 7 6 8 2 4 9 11 3 10 5 12

到这里都可以全部答对的话,对我们的事件循环已经有了较好的认识啦!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值