美文网首页
浏览器的事件循环机制(Event Loop)

浏览器的事件循环机制(Event Loop)

作者: 凯凯frank | 来源:发表于2020-02-09 23:56 被阅读0次

    js是一门单线程非阻塞的脚本语言
    单线程意味着,js在执行的时候,只有一个主线程来处理所有的任务。
    非阻塞则是当代码需要进行一项异步任务(如I/O事件、网络请求)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果后,将注册的回调函数放入任务队列中,等待主线程空闲的时候(调用栈被清空),再根据一定的规则读取任务队列中的任务。

    任务队列分为两种:宏任务(macro task)和微任务(micro task)。

    宏任务和微任务

    宏任务,macrotask,也叫tasks。
    包括:script全部代码、setTimeout、setInterval、requestAnimationFrame (浏览器独有)、I/O、UI rendering (浏览器独有)

    微任务,microtask,也叫jobs。
    包括:Promise、ajax、Object.observe(废弃)、MutationObserver

    事件执行顺序(也可以直接看下面的简单版本):

    1. 执行全局的同步代码,全局Script代码执行完毕后,调用栈Stack会清空;
    2. 依次从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,直到直到把microtask queue中的所有任务都执行完毕。(如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行) 。microtask queue中的所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空;
      3.如果需要的话,渲染页面;
      4.取出宏队列macrotask queue中位于队首的任务,放入Stack中执行;执行完毕后,调用栈Stack为空;
      重复第2-4步骤;
      ......

    简单的来说,事件循环是指: 先执行一次宏任务,然后清空微任务列表,然后需要的话,渲染页面,然后循环上面的步骤。如下图


    eventLoop.png

    练习题目

    console.log(1);
    
    setTimeout(() => {
      console.log(2);
      Promise.resolve().then(() => {
        console.log(3)
      });
    });
    
    new Promise((resolve, reject) => {
      console.log(4)
      resolve(5)
    }).then((data) => {
      console.log(data);
    }).then((data) => {
      console.log('another');
    })
    
    setTimeout(() => {
      console.log(6);
    })
    
    console.log(7);
    

    正确答案

    1
    4
    7
    5
    another
    2
    3
    6
    

    解析:

    首先1 4 7属于全局的同步代码,先执行。注意new Promise的时候也属于同步执行。
    然后再执行微任务队列中所有的任务,即5, 此时又向微任务队列中添加了一个任务,一并在此周期内被调用执行,即 another
    然后要取出一个宏任务队列中的任务,即2
    然后再执行微任务队列中所有的任务, 即3
    然后要取出一个宏任务队列中的任务,即6

    相关文章

      网友评论

          本文标题:浏览器的事件循环机制(Event Loop)

          本文链接:https://www.haomeiwen.com/subject/tlloxhtx.html