• 说说 event loop


    说说event loop

    首先,js是单线程的,主要的任务是处理用户的交互,而用户的交互无非就是响应DOM的增删改,使用事件队列的形式,一次事件循环只处理一个事件响应,使得脚本执行相对连续,所以有了事件队列,用来储存待执行的事件,那么事件队列的事件从哪里被push进来的呢。那就是另外一个线程叫事件触发线程做的事情了,他的作用主要是在定时触发器线程、异步HTTP请求线程满足特定条件下的回调函数push到事件队列中,等待js引擎空闲的时候去执行,当然js引擎执行过程中有优先级之分,首先js引擎在一次事件循环中,会先执行js线程的主任务,然后会去查找是否有微任务microtask(promise),如果有那就优先执行微任务,如果没有,在去查找宏任务macrotask(setTimeout、setInterval)进行执行

    众所周知 JS 是门非阻塞单线程语言,因为在最初 JS 就是为了和浏览器交互而诞生的。如果 JS 是门多线程的语言话,我们在多个线程中处理 DOM 就可能会发生问题(一个线程中新加节点,另一个线程中删除节点)

    • JS 在执行的过程中会产生执行环境,这些执行环境会被顺序的加入到执行栈中。如果遇到异步的代码,会被挂起并加入到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为

    console.log('script start');
    
    setTimeout(function() {
      console.log('setTimeout');
    }, 0);
    
    console.log('script end');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask)。在 ES6 规范中,microtask 称为 jobsmacrotask 称为 task

    console.log('script start');
    
    setTimeout(function() {
      console.log('setTimeout');
    }, 0);
    
    new Promise((resolve) => {
        console.log('Promise')
        resolve()
    }).then(function() {
      console.log('promise1');
    }).then(function() {
      console.log('promise2');
    });
    
    console.log('script end');
    // script start => Promise => script end => promise1 => promise2 => setTimeout
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    以上代码虽然 setTimeout 写在 Promise 之前,但是因为 Promise 属于微任务而 setTimeout 属于宏任务

    微任务

    • process.nextTick
    • promise
    • Object.observe
    • MutationObserver

    宏任务

    • script
    • setTimeout
    • setInterval
    • setImmediate
    • I/O
    • UI rendering

    宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话就先执行微任务

    所以正确的一次 Event loop 顺序是这样的

    • 执行同步代码,这属于宏任务
    • 执行栈为空,查询是否有微任务需要执行
    • 执行所有微任务
    • 必要的话渲染 UI
    • 然后开始下一轮 Event loop,执行宏任务中的异步代码

    通过上述的 Event loop 顺序可知,如果宏任务中的异步代码有大量的计算并且需要操作 DOM 的话,为了更快的响应界面响应,我们可以把操作 DOM 放入微任务中

  • 相关阅读:
    在 Kubernetes 上最小化安装 KubeSphere
    不要老想着重置!当你忘记Wi-Fi密码时,可以尝试这些办法
    Linux常用的磁盘使用情况命令汇总
    HTML瀑布流布局实现网易LOFTER——masonry响应式网格布局库(非jQuery)
    tns-12545 tns-12560 tns00515 linux error 99
    抖音商家找达人带货怎么给链接?抖音带货操作方法分享
    美国C1/D签证如何申请?
    关于spring项目中,security 对websocket请求和拦截问题
    从GitHub火到头条!这套万人期待的 JAVA 小白成神之路PDF,终于开源了!
    Apacha Flume
  • 原文地址:https://blog.csdn.net/php_martin/article/details/125767793