欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript Event Loop和微任务、宏任务

程序员文章站 2023-11-17 15:23:22
为什么JavaScript是单线程? JavaScript的一大特点就是单线程, 同一时间只能做一件事情,主要和它的用途有关, JavaScript主要是控制和用户的交互以及操作DOM。注定它是单线程。 假如是多个线程, 一个移除DOM节点,一个新增DOM节点,浏览器以谁的为准呢? 什么是执执行栈呢 ......

为什么javascript是单线程?

javascript的一大特点就是单线程, 同一时间只能做一件事情,主要和它的用途有关, javascript主要是控制和用户的交互以及操作dom。注定它是单线程。 假如是多个线程, 一个移除dom节点,一个新增dom节点,浏览器以谁的为准呢?

什么是执执行栈呢?

函数的调用就会形成一个栈帧。当执行栈都为空的时候,主线程就会处于空闲状态。

   function fn2(x, y) {
      return x + y  
   } 
   
   function fn1(z) {
     let a = 10
     return fn2(a, z)
   }
   
   console.log(fn1(5)) // 15

以上代码: fn1 函数调用时会创建一个执行栈,栈中包含fn1的参数和局部变量。当 fn1 调用 fn2 时, 第二个执行栈就会被创建, 并且压入到第一个执行栈之前。 栈中包含了 fn2的参数和全局变量。当 fn2执行完返回时,最前面的执行栈就会被弹出。剩下 fn1 函数的调用帧, 当fn1 函数执行完并返回时, 执行栈就空了。

任务队列

任务队列主要用户挂起等待中的任务(异步任务)。
javascript是单线程, 意味着所有的任务需要排队, 前一个任务执行完,才能进行下一个任务。 ajax就是典型的异步任务,需要调用http线程,然后发送request请求,再是等待服务端的响应。在结果没有返回执行,后面的代码是不会执行的,这会给用户一种网站卡的现象。

因此, javascript 分为 同步任务在主线程上排队执行的任务,也就是前面执行完毕,才能执行下一个的任务。 异步任务是指它不会进行主线程,不会影响后续代码的执行,而是进入任务队列,当异步任务执行有了结果,就会在任务队列中放置一个事件,等主线程空闲(执行栈为空,同步任务执行完毕),通知任务队列进入主线程执行。

微任务和宏任务

任务队列中的异步任务分为 微任务宏任务
常见的微任务有: process.nexttickpromisemutationobserver监听dom的变化。

常见的宏任务: settimeoutsetintervalsetimmediatescript中整体的代码、 i/o操作ui渲染等。

微任务和宏任务的区别:

  • 微任务进入主线程执行是一队一队的, 而宏任务进入主线程是一个一个的。
  • 微任务是在主线程空闲时批量执行, 宏任务是在事件循环下一轮的最开始执行

例子: 以下代码的打印结果

    console.log(1)
    settimeout(function() {
        console.log(2)
    })
    
    promise.resolve()
        .then(function() {
            console.log(3)
        })
    
    console.log(4)
    
   // 打印结果: 1 4 3 2

整个的执行过程:

    stack(执行栈)、micro(微任务)、macro(宏任务)

    1.初始状态: stack:[], micro: [], macro: [script]。执行栈为空, 微任务为空, 宏任务队列中有一个整体的 script代码 
    
    2. 主线程开始执行, 遇到console.log(1), 首先会打印 1 
    
    3. 继续向下执行,遇到 settimeout异步任务,就将其加入到macro(宏任务)队列中。等待执行 
    
    4. 继续向下执行, 遇到 promise.resolve也是一个异步任务,单它是微任务,将其加入 micro(微任务)队列中,等待着行 
    
    5. 解析console.log(4), 并且打印4。 当主线程执行完打印的结果依次是 1 和 4。
    
    6. 这时候主线程就会问 任务(异步)队列,有没有微任务要执行,将所有的 micro(微任务)加入执行栈执行, 打印结果 3
    
    7. 微任务执行完了, 就开始下一轮事件循环, 将第一个 macro(宏任务)压入执行栈执行, 再次打印 2。 

event loop事件循环

JavaScript Event Loop和微任务、宏任务

只要主线程一空闲就会将 "任务队列中的异步任务"依次压入执行栈, 这个过程是循环不断的,所以整个运行机制称之为 event loop(事件循环)。

执行栈中(stack)的代码(同步任务),总是在读取"任务队列"(异步任务)之前执行。

图示

JavaScript Event Loop和微任务、宏任务

参考文章