EventLoop浏览器事件循环

209 阅读3分钟

1. 进程和线程

  • 一个进程中可能包含多个线程

  • 进程:程序(浏览器打开一个页面,就会开辟一个进程)

  • 线程:处理任务,一个线程同事只能处理一个任务

  • 浏览器是多线程的

    • HTTP网络线程:用于资源文件的加载
    • GUI渲染线程:用于页面自上而下的渲染,最后绘制出页面
    • JS渲染线程:专门用于渲染js代码
  • JS是单线程的

    • 浏览器只会开辟一个线程来渲染js代码,所以js的本质都是同步的,一件一件,不能同时处理两件事
  • js中是有异步编程代码的

    • 此处的异步编程不是同时处理多件事,是基于浏览器的多线程性,结合event loop事件循环机制,构建出来的异步效果
  • js中异步编程的代码

    • 宏任务
      • 定时器:设置定时器是同步的,间隔时间后,触发绑定方法执行是异步的
      • 事件绑定:监听事件触发
      • ajax/fetch创建的网络请求,从服务器请求数据
    • 微任务
      • Promise:then/resolve/reject
      • async/await
// 定时器的返回值是一个数字,代表当前系统中第几个定时器,清除时候,也是基于这个数字清除
let n = 0;
let timer = setTimeout(() => {
  n++;
  console.log(n);
}, 1000)
console.log(timer)  // 1
console.log(n)  // 0
// 1 0 1

1.1 代码入队列过程

  • 正常情况下,js渲染线程

  • 先进行词法分析,把页面中即将要自上而下执行的代码都分析为一个个的任务,不管同步异步,放在任务队列的宏任务中

  • 词法分析结束后,再从宏任务队列中,拿出来,把代码自上而下,逐一执行

  • 代码执行过程中,只要创建一个异步的任务,则会把这个异步任务放到等待任务队列中EventQueue

  • 宏任务队列按照达到条件去执行

  • 微任务队列按照存放先后顺序去执行

image.png

1.2 eg

image.png

  • 输出2 然后死循环

image.png

1.3 async/await

  • async的作用
    • 让一个函数返回一个Promise实例(默认成功状态),除非本身返回一个Promise实例,最终结果以返回的Promise实例为准
function fn() {
  return 10
}
console.log(fn())  // => 10

async function fn1() {
  return 10
}
console.log(fn1())  
// => promise,[[PromiseState]] -> fulfilled, [[PromiseResult]] -> 10

fn1().then ...
  • 函数中如果需要使用await,则必须基于async使用
  • await可以把一个异步的编程模拟成同步的效果
    • await后面一般会放置一个异步的Promise实例(其他值也可以)
    • 会等待Promise状态为成功后,获取成功的结果,并且执行函数体中await
    • 如果await后的promise是失败的,则不再处理下面的,用try catch处理
function handle() {
  return new Promise(resolve=> {
    setTimeout(()=> {
      resolve('OK')
    }, 1000)
  });
}

async function fn() {
  // 先执行handle,返回一个promise实例
  // 等待promise变成成功态,此时await下面代码都不执行
  await result = await handle();
  console.log(result);
  
  // 此处加了await,同步代码也需要等同步任务执行完再执行
  // await后面的代码当作promise异步处理,状态变为成功后执行
  let n = await 10;
  console.log(n);
  
  let m = await Promise.resolve('NO')
  console.log(m)
  
  // await后面实例是失败的,则不再处理之前存放的微任务,不处理失败,浏览器会抛异常
  try {
    let q  = await Promise.reject('NO')
    console.log(q)
  } catch(err) {
  }
}
// 输出 2 1
// fn执行遇到await,await紧跟着的立即处理,把后面代码放到微任务中,需要等promise成功后处理
async function fn() {
  await 10;
  console.log(1);
}
fn();
console.log(2);

image.png

1.4 一个事件完全执行完,才去下一个事件

  • 一个事件中的同步,微任务执行完,才会执行下一个事件
  • 2 1 4 3

image.png

1.5 eg5

image.png

1.6 eg6

  • 下一个then要等上一个then的结果,task4需要等到task5返回的结果
  • b f c a d

image.png

1.7 eg

image.png

image.png