事件循环机制

72 阅读2分钟

进程和线程

进程:指程序运行专属的内存空间

线程:指每一个进程中的线程(至少一个主线程)

浏览器属于多进程,每一个网页代表着创建一个独立的进程,包含渲染主线程(GUI线程):渲染浏览器界面(即HTML、CSS、JS代码解析)

事件循环

JS单线程运行,异步基于回调来实现,事件循环其实是异步回调的实现原理

从前往后一行一行执行,某一行报错停止执行之后的代码,先执行同步再继续执行异步

如图示:

  • Call Stack:调用栈
  • Web APIs:浏览器之外定义的相关API(如定时器,事件监听)
  • Event Loop:事件轮询
  • Callback Queue:回调函数队列(消息队列)

在这里插入图片描述

示例:

console.log('hello')
setTimeout(function call(){
	console.log('你好')
},3000)
console.log('Bye')
// code...
  1. 首先会将 console.log('hello') 推入调用栈中并执行,完成打印hello,并清空调用栈;
  2. setTimeout推入调用栈执行,在web api中生成定时器并标记call回调,setTimeout 执行完毕并清空调用栈,待定时器时间完成后将回调call函数推入Callback Queue(消息队列)中等待执行;
  3. 执行console.log('Bye')以及所有的同步代码
  4. 当同步代码全部执行完毕(调用栈为空),将启动Event Loop机制(轮询查找),询问Callback Queue是否有任务,并将任务(函数call)推送到调用栈执行

同步代码一行一行在调用栈中执行(死循环导致阻塞),遇到异步任务会先进行记录,等待时机(定时,网络请求,事件监听),时机成熟移动到Callback Queue中,当调用栈为空Event loop开始工作,轮询查找Callback Queue,将查找的任务推送到调用栈中执行,然后继续轮询。

消息队列

宏任务: 定时器,ajax,DOM事件
微任务: Promise async / await (微任务优先级高于宏任务)

  1. 每次调用栈清空(Event Loop每一次轮询结束),即同步任务执行完毕;
  2. 浏览器都会尝试进行DOM渲染,然后再触发Event Loop。
  3. WebAPI:DOM( 文档对象模型 )、 BOM、事件绑定、ajax、存储

宏任务: DOM 渲染后触发

  1. 调用栈(Call Stack清空)
  2. 执行当前微任务:Promise是ES规范并非W3C规范,不会经过Web APIs会直接进入micro task queue
  3. 尝试 DOM渲染
  4. 触发 Event Loop

微任务:DOM渲染前触发

  1. 调用栈(Call Stack清空)
  2. 尝试DOM渲染
  3. 触发Event Loop