面试题 - 事件循环机制

面试题 - 事件循环机制

一、浏览器JS异步执行的原理

一般常说js是一门单线程语言,那为什么可以异步执行且不发生阻塞呢?

  • 常说的JS是单线程语言,是因为执行JS的引擎是单线程的,而浏览器本身是多线程的
  • 浏览器主要含有:
    • js 执行线程
    • 定时器线程
    • http 请求线程
    • 事件触发线程
    • GUI 线程等
  • 异步请求的真正执行者是浏览器的其他线程
  • js 引擎只是执行了异步操作成功了之后的回调函数

二、事件循环机制

1 - 执行栈和任务队列

(1)执行栈是什么

  • 用于按执行顺序存放同步代码
  • 按序执行,执行完毕后弹出执行栈
  • 如果在执行过程中遇到异步操作,就交给其他线程处理

(2)任务队列

  • 用于按序排放异步操作执行结束后的回调函数
  • 任务队列中的函数等待执行栈执行结束后取出执行

2 - 事件循环的本质

  • 基于事件驱动模式
  • 至少包含了一个事件循环来判断当前的任务队列是否有新的任务
  • 通过不断的循环取出异步回调进行执行

3 - 宏任务和微任务

(1)宏任务的分类

  • 渲染事件
  • 用户交互事件
  • SetTimeout、setInterval
  • 网络请求、文件读写等

有明确异步操作的任务,需要其他的异步线程支持

(2)微任务的分类

  • promise.then promise.catch
  • process.nextTick

没有明确的异步任务需要执行,只有回调不需要其他异步线程的支持

(3)执行顺序

  • 在同步代码执行结束后
  • 先执行微任务队列中的微任务
  • 再执行宏任务队列中的宏任务

(4)案例

console.log('同步代码1');
setTimeout(() => {
    console.log('setTimeout')
}, 0)
new Promise((resolve) => {
  console.log('同步代码2')
  resolve()
}).then(() => {
    console.log('promise.then')
})
console.log('同步代码3');

// 最终输出"同步代码1"、"同步代码2"、"同步代码3"、"promise.then"、"setTimeout"
setTimeout(() => {
  console.log('setTimeout start');
  new Promise((resolve) => {
    console.log('promise1 start');
    resolve();
  }).then(() => {
    console.log('promise1 end');
  })
  console.log('setTimeout end');
}, 0);
function promise1() {
  return new Promise((resolve) => {
    console.log('promise2');
    resolve();
  })
}
async function async1() {
  console.log('async1 start');
  await promise1();
  console.log('async1 end');
}
async1();
console.log('script end');

// 输出结果
async1 start
promise2
script end
async1 end
setTimeout start
promise1 start
setTimeout end
promise1 end

4 - 定时器误差

(1)执行顺序

  • 遇到一个定时器请求,开启定时器线程去计时
  • 计时结束后将回调函数放入到任务队列(宏任务)
  • 等待同步任务执行 waiting… ,在同步任务执行结束后可能还有微任务
  • 同步任务执行结束后取出任务队列中的回调

(2)误差大小

  • 定时器的误差值取决于同步任务的执行时间 + 微任务的执行时间
  • 同步任务执行时间越长,定时器的误差越大

三、脑图总结

面试题 - 事件循环机制_第1张图片

你可能感兴趣的:(前端面试题,javascript,面试题,知识点)