1. 浏览器中的事件循环

当我们书写的javascript代码,通过浏览器进行加载到渲染页面,再到页面交互,清楚我们代码中的执行顺序谁先谁后对我们来说尤为重要.
这部分知识就涉及到浏览器的事件循环

1. 进程和线程

2. 异步和同步

  1. 同步: 代码自上而下执行,上面代码没有执行完毕,下面的代码不会被执行
  2. 异步: 异步是相对同步而言的。上面代码执行过程中不会 阻塞代码的执行。
  3. 像在浏览器的渲染过程中js主线程执行栈会执行同步代码和异步代码 同步代码按照顺序自伤而下开始执行, 遇到异步代码 当前的主线程会吊起另一个线程 定时器就开启定时器线程 http请求就开启http请求线程...。 定时器webAPI在触发等待事件会将当前的定时器函数存储在内存中的红黑树中,在定时器时间到达的时候取出来 压入当前的主线程执行栈中 开始执行定时器中的代码。
  4. 在当前的执行任务中 如果当前执行栈中同步代码发生了阻塞,那么后续的异步执行代码将不会被执行 除非等待当前的同步任务执行完毕 才会按照原异步任务加入队列的顺序开始进行下一个异步任务,直到异步任务执行完毕后,事件循环执行完毕。
       // 同步代码不执行完毕。 异步代码不会被执行
      setTimeout(() => {
        // 因为死循环 异步代码不会被执行
        document.body.style.background = 'red'
      }, 0);
      while(true) {
    
      }
    

宏任务和微任务

  1. 宏任务是有宿主环境提供的
  2. 微任务是有语言本身进行提供的
  3. 在上一个所说的等待加入执行栈的任务其实是一个宏任务。用于做异步回调的逻辑执行。
1. 常见的微任务:Promise.then() MutationObserver queueMicrotask node中的process.nextTick()
2. 常见的宏任务: 事件 http请求 定时器 ui渲染 setImmidiate requestAnimationFrame等

事件循环调用栈图

常见面试题

   document.body.style.background = 'red'
   console.log(1)
   Promise.resolve().then(() => {
    console.log(2)
    document.body.style.background = 'yellow'
  })
  console.log(3)
  黄色还是红色到黄色的过渡?
   btn.addEventListener('click', function() {
       console.log('listener1')
       Promise.resolve().then(() =>{
         console.log('micro task1')
       })
     })
     btn.addEventListener('click', function() {
       console.log('listener2')
       Promise.resolve().then(() =>{
         console.log('micro task2')
       })
     })
     btn.click()
  1. btn.click()执行时js调用栈在执行的时候js线程会对addEventListener会合并执行,不牵涉到宏任务,所以输出时listener1 listener2 micro task1 micro task2
  2. 当我们注释 btn.click()进行点击按钮触发 由于浏览器中点击事件时宏任务,所以会牵涉到事件循环队列,这时候输出就是 listener1 micro task1 listener2 micro task2
    console.log(1)
     async function async1() {
       console.log(2)
       await console.log(3)
       console.log(4)
     }
     setTimeout(() => {
       console.log(5)
     }, 0);

     const promise = new Promise((resolve) => {
       console.log(6)
       resolve(7)
     })
     promise.then(res => {
       console.log(res)
     })
     async1()
     console.log(8)