zoukankan      html  css  js  c++  java
  • 浅谈 Event loop (事件循环)

    从Event Loop谈JS的运行机制

    先来理解一个概念:

    • JS分为同步任务和异步任务

    • 同步任务都在主线程上执行,形成一个执行栈 Execute Content Stack

    • 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列(根据MDN准确的说应该是消息队列 message queue)之中放置一个消息(一般都是异步的回调函数)。

    • 一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取消息队列,将可运行的异步任务添加到可执行栈中,开始执行。

    看图:

    看到这里,应该就可以理解了:为什么有时候setTimeout推入的事件不能准时执行?因为可能在它推入到消息队列时,主线程还不空闲,正在执行其它代码,所以自然有误差。

    事件循环机制进一步补充

    这里就直接引用一张图片来协助理解:(参考自Philip Roberts的演讲《Help, I’m stuck in an event-loop》)

    上图大致描述就是:

    • 主线程运行时会产生执行栈,栈中的代码调用某些api时,它们会在事件队列中添加各种事件(当满足触发条件后,如ajax请求完毕)

    • 而栈中的代码执行完毕,就会读取事件队列中的事件到执行栈中,去执行那些回调

    • 如此循环

    • 注意,总是要等待栈中的代码执行完毕后才会去读取消息队列中的消息

    然后我们通过阅读Promise/A+规范,可以得知JS中分为两种任务类型,分别是macro-task和micro-task。

    Macro-tasks包括: script(整体代码)、setTimeout, setInterval, setImmediate, I/O, UI Rendering;(可以看到,事件队列中的每一个事件都是一个macrotask)

    Micro-tasks包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver。

    总结下运行机制:

    • 执行一个宏任务(栈中没有就从事件队列中获取)

    • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中

    • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)

    • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染

    • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

    如图:

     这里注意的是,UI Rendering是在micro-task之后执行,需要在UI渲染之前执行的逻辑,一般采用micro-task异步回调方式进行调用。 同样,micro-task队列不宜过长,给micro-task队列添加过多回调阻塞macro-task队列的任务执行是小事,重点是这有可能会阻塞UI Render,导致页面不能更新。浏览器也会基于性能方面的考虑,对micro-task中的任务个数进行限制。

    参考文章:

  • 相关阅读:
    智能问答系统构思(持续更新)
    软件测试
    Android实现智能问答机器人(四) -----连接我们的系统
    软件架构模式---分层架构V2.0
    软件架构模式---分层架构
    PHP文件上传示例
    PHP文件上传常见类型checklist
    PHP操作Mysql数据库查询数据实例
    PHP操作Mysql数据库更新数据实例
    PHP 操作Mysql数据库删除数据示例
  • 原文地址:https://www.cnblogs.com/zhilingege/p/8652210.html
Copyright © 2011-2022 走看看