• Event loop


    复习一下之前看过Event loop

     首先说一下为啥有这个东西.

       因为JavaScript是单线程的,也就是只能顺序执行,当时当我们某一个点需要的等待的时间比较长的时候,那我们的页面就会卡顿,下面的逻辑以及处理也都会进行等待,这个时候就有了Event loop的加入,

    js为什么是单线程的?

      通俗一点来讲就是:js更多的是和用户进行交互,那如果再一个计划没有执行完,再次执行了下一个计划,而第二个计划又依赖与第一个计划的时候,那我们的页面就会出现问题,给用户不完美的体验

    有了它(Event loop)我们能做什么?

        举个例子:当我们去请求数据的时候,犹豫后台反应慢或者数据大,那我们再请求的时候所花费的时间就会比较长,那我们再请求的时候能做其它的吗?答案当然是可以了,借用之前以为大佬说过的话,没有代码实现不了的,有,就是你接触的还不够深.  

      Javascript是单线程的,单线程就意味着所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

    如果其中一个任务很慢,占用了很多的时间,此时网页就可能卡住

    有些 I/O (输入输出) 操作是很慢的,比如 Ajax 操作从网络读取数据

    JS 语言的设计者意识到,主线程可以不管这些 I / O 操作,把等待中的任务挂起,先运行排在后面的任务。等待 I / O 操作返回结果,再去执行挂起的任务

    因此任务可以分为两种,一种是同步任务,一种是异步任务

    同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务

    异步任务指的是,不进入主线程,而是进入任务队列,通过 Event Loop 机制等待合适的时间调用

    有了 Event Loop 的加持,JS 才能非阻塞地运行

    以上是js的Event loop,

    那么浏览器是否有自己的Event loop呢?答案也是有的,

    浏览器的Event loop

    首先看一张图

    先别被这张图吓坏,看看执行一个 JavaScript 代码的具体流程

    1. 执行全局 Script 代码,这些代码中有同步语句或异步语句,遇到同步语句直接执行,异步语句放入宏任务或微任务的队列。
    2. 全局 Script 代码执行完毕后,调用栈 Stack 会清空
    3. 从微任务中取出位于队首的回调任务,放入调用栈 Stack 中执行,执行完成后 微任务队列长度减一
    4. 继续取出位于队首的任务,放入调用栈 Stack 中执行,以此类推,直到把 微任务队列 中的所有任务都执行完毕。注意,如果在执行微任务过程中,又产生了新的微任务,那么会加入到微任务队列的尾部,也会在这个周期被执行
    5. 当 微任务队列 中的所有任务都执行完毕后,此时 微任务队列 为空,调用栈 Stack 也会空
    6. 取出宏任务中的队首的任务放入 Stack 中执行
    7. 执行完毕后,调用栈Stack为空
    8. 重复第3-7个步骤
    9. 重复第3-7个步骤
    10. ...

    可以看到,这就是浏览器的事件循环 Event Loop

    这里归纳3个重点:

    1. 宏任务一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务;
    2. 微任务队列中所有的任务都会被依次取出来执行,直到 微任务队列 为空;
    3. 图中没有画UI rendering的节点,因为这个是由浏览器自行判断决定的,但是只要执行UI rendering,它的节点是在执行完所有的 微任务 之后,下一个 宏任务 之前,紧跟着执行UI render。

    下面看一下小例子:

    console.log(1);
    
    setTimeout(() => {
      console.log(2);
      Promise.resolve().then(() => {
        console.log(3)
      });
    });
    
    new Promise((resolve, reject) => {
      resolve(4)
    }).then((data) => {
      console.log(data);
    })
    
    setTimeout(() => {
      console.log(5);
    })
    
    console.log(6);

    以上建议先自己看一下,然后再看答案,

    以上执行顺序: 

    console.log(1);这个应该是没有疑问的吧,第一个执行,它再最顶端  并且是属于微任务的.
    然后呢碰到了
    setTimeout;这个属于宏任务,滚到一边去
    接下来是new Promise;这个属于微任务里面没有微任务,加入队列
    new Promise().then属于宏任务,滚到一边
    setTimeout属于宏任务,滚到一边
    console.log(6);微任务  立即执行
    到这里所有的微任务执行完毕,开始执行宏任务
    拿到第一个setTimeout,里面有微任务,执行,微任务执行完执行宏任务
    然后只剩下一个
    setTimeout


    最后执行顺序:1.6.4.2.3.5


    总结:

    1. JavaScript 是单线程的,有了 Event Loop 的加持,JS 才可以非阻塞地执行
    2. 浏览器的 Event Loop 机制,分为 宏任务 和 微任务
    3. 微任务比宏任务优先级高,事件循环开始后,微任务首先执行,直到微任务队列清空,然后执行宏任务队列,如果宏任务队列执行过程中,产生了新的微任务,需要立刻执行微任务,直到微任务队列清空,然继续执行宏任务,直到宏任务队列清空
    4. 宏任务: setTimeout、setInterval、requestAnimation(浏览器)、IO、UI rendering
    5. 微任务: process.nextTick(Node)、Promise、Object.observe、MutationObserver
  • 相关阅读:
    Step download timeout (120 sec)
    Error -27740: WSA_IO_pending
    Message Code 【27796】 Failed to connect to server 'hostname';port_ld': 'reason'.
    Error -27780: Connection reset by peer: socket write error
    LoadRunner性能分析指标解释
    Firefox 在LR录制过程中添加例外的问题解决方法
    -27979 LoadRunner 错误27979 找不到请求表单 Action.c(73): Error -27979: Requested form not found
    MySQL测试环境遇到 mmap(xxx bytes) failed; errno 12解决方法
    基于Apache搭建Nagios图形监控
    自动安装脚本-------------基于LVMP搭建Nagios 监控
  • 原文地址:https://www.cnblogs.com/wgs-blog/p/14977352.html
Copyright © 2020-2023  润新知