Published on

事件循环

Authors
  • avatar
    Name
    noodles
    每个人的花期不同,不必在乎别人比你提前拥有

简介

事件循环是不同的宿主环境(浏览器或node)对javascript任务进行调度的一种机制,在讨论事件循环的时候首先应该区分node和浏览器(不同宿主环境实现的事件循环机制不同).下面通过介绍一些javascript的基础知识,进而简单的介绍浏览器中的事件循环和node中事件循环.

基本概念

  1. javascript程序的执行机制是通过栈来管理的.当进入一个函数,就创建了这个函数的执行环境并将这个执行环境推入栈顶,执行完当前的函数后,从栈顶移除对应的执行环境,进入到外层的执行环境. stack
  2. javascript的执行是单线程的.但是由于整个事件循环的调度,赋予了javascript对异步任务的强大处理能力.对于异步任务(网络请求,按钮点击)javascript代码调用宿主环境提供的api,将异步任务交给其他的线程去完成.当对应的异步任务完成的时候,将回调函数添加到 回调函数的队列中,由事件循环来实现会回调函数的调用. loop

marcotasks microtasks

将macrotasks和micortasks单拉出来讲解,是因为理解好这点能更好的理解浏览器或node的任务队列.在实际的实现环境中不同的任务可以放置在不同的任务队列中,然后通过对多个任务队列的调用来完成整个事件循环.

  1. macrotasks:
  • 定时器(timer) setTimeout setInterval setImmediate
  • message channel (message channel执行的优先级高于timer)
  • I/O
  • UI rendering
  1. microtasks:
  • Promises
  • MutationObserver(监听DOM)
  1. 其他api
  • queueMicrotask(fn) 将Fn推入微任务执行队列
  • requestAnimationFrame
    通知浏览器在下次重绘之前调用传入的回调函数,回调函数默认传入函数执行的时间戳.requestAnimationFrame不属于宏任务和微任务,在微任务执行之后执行
  • process.nextTick process.nextTick是node上的api,具体的执行时机是在微任务之前执行。 nextTick
        setTimeout(function(){
          console.log(1);
        });
        new Promise(function(resolve){
          console.log(2)
          for( var i=100000 ; i>0 ; i-- ){
              i==1 && resolve()
          }
          console.log(3)
        }).then(function(){
          console.log(4)
        });

        console.log(5);
        process.nextTick(() => { console.log('nextTick'); })
        输出的顺序依次是 2 3 5 nextTick 4 1
  • requestIdleCallback window.requestIdleCallback(callback[, options])
    1. callback是一个在事件循环空闲时即将被调用的函数的引用,接收一个IdleDeadline参数,通过该参数可以获取当前空闲时间(timeRemaining())以及回调是否在超时时间前已执行的状态(didTimeout)
    2. options 可选参数 可以配置timeout 表示超时毫秒数未调用回调函数,回调函数将在下一次空闲期间被强制执行。

在具体的实现中只会有一个microTasks队列,简单的理解事件循:

  1. 浏览器或者node会按照顺序执行自己环境的多个macrotasks队列
  2. 每执行完一个macrotask队列就会拿出micortasks队列的任务全部执行,然后继续执行下一个macrotask队列
runTask

event loop in browser

其实通过对上面相关的知识的介绍,已经可以大致的了解浏览器中事件循环的任务队列 主要有以下几种macrotasks队列

  1. 事件callback
  2. I/O(xhr)
  3. timers
  4. UI渲染
loop

event loop in node

node

注意点

  1. 在浏览器或者node中某些代码的执行会导致event loop失效(停留在处理一个事件队列导致无法进入其他的事件队列的处理).比如浏览器中javascript的长时间执行会导致UI无法交互,node中process.nextTick的递归调用

相关资料

通过microtasks和macrotasks看JavaScript异步任务执行顺序
libuv Design overview How JavaScript works in browser and node? Tasks, microtasks, queues and schedules
Further Adventures of the Event Loop - Erin Zimmer - JSConf EU 2018 菲利普·罗伯茨:到底什么是Event Loop呢? | 欧洲 JSConf 2014
「Nodejs万字进阶」一文吃透异步I/O和事件循环