zoukankan      html  css  js  c++  java
  • Js事件循环(Event Loop)机制

    前言

    Event Loop是计算机系统的一种运行机制,是个很重要的概念。而JavaScript用这种机制来解决单线程运行带来的问题。理解很熟悉将会有利于我们更容易理解vue的异步事件。

    JavaScript是单线程的

    1、什么是单线程?

    单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。简单来说,即同一时间只能做一件事件。

    2、js为什么是单线程?

    js是一种运行在网页的简单的脚本语言,由于设计的初衷是作为浏览器脚本语言,用于与用户互动,以及操作DOM。这决定它是单线程的。

    3、单线程带来的问题?

    单线程就意味着,所有任务都需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就需要一直等着。这就会导致IO操作(耗时但cpu闲置)时造成性能浪费的问题。

    4、如何解决单线程的性能问题?

    采用异步可以解决。主线程完全可以不管IO操作,暂时挂起处于等待中的任务,先运行排在后面的任务。等到IO操作返回了结果,再回过头,把挂起的任务继续执行下去。于是,所有任务可以分成两种,一种是同步任务,另一种是异步任务。

    执行栈和任务队列

    执行栈

    当执行某个函数、用户点击一次鼠标,Ajax完成,一个图片加载完成等事件发生时,只要指定过回调函数,这些事件发生时就会进入执行栈队列中,等待主线程读取,遵循先进先出原则。

    任务队列

    当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列。需要注意的是异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。

    事件循环(Event Loop)

    JavaScript内存模型

    在了解事件循环之前,先要弄明白Js的内存模型,这有助于更好的理解事件循环。

    • 调用栈(Call Stack):用于主线程任务的执行。
    • 堆(Heap):用于存放非结构数据,如程序分配的变量和对象。
    • 任务队列(Queue): 用于存放异步任务。

    Js异步执行的运行机制

    1. 所有同步任务都在主线程上执行,形成一个执行栈。
    2. 主线程之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列之中放置一个事件。
    3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
    4. 主线程不断重复上面的第三步。

    任务队列

    异步任务分为 宏任务(macrotask)与微任务(microtask),不同的API注册的任务会依次进入自身对应的队列中,然后等待Event Loop将它们依次压入执行栈中执行。

    • 宏任务主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、setImmediate(Node.js 环境)
    • 微任务主要包含:Promise、MutaionObserver、process.nextTick(Node.js 环境)

    我们的JavaScript的执行过程是单线程的,所有的任务可以看做存放在两个队列中——执行队列和事件队列。

    执行队列里面是所有同步代码的任务,事件队列里面是所有异步代码的宏任务,而我们的微任务,是处在两个队列之间。

    当JavaScript执行时,优先执行完所有同步代码,遇到对应的异步代码,就会根据其任务类型存到对应队列(宏任务放入事件队列,微任务放入执行队列之后,事件队列之前);当执行完同步代码之后,就会执行位于执行队列和事件队列之间的微任务,然后再执行事件队列中的宏任务。

    实例

    new Promise(resolve => {
        resolve(1);
        
        Promise.resolve().then(() => {
            // t2
            console.log(2)
        });
        console.log(4)
    }).then(t => {
        // t1
        console.log(t)
    });
    console.log(3);

    这段代码的流程大致如下:

    1. script 任务先运行。首先遇到Promise实例,构造函数首先执行,所以首先输出了 4。此时 microtask 的任务有 t2 和 t1
    2. script 任务继续运行,输出 3。至此,第一个宏任务执行完成。
    3. 执行所有的微任务,先后取出 t2 和 t1,分别输出 2 和 1
    4. 代码执行完毕

    综上,上述代码的输出是:4321

    广州品牌设计公司https://www.houdianzi.com PPT模板下载大全https://redbox.wode007.com

    事件循环

    主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

    从上图我们可以看出:

    • 主线程运行的时候,产生堆(heap)和栈(stack)。
    • 栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。
    • 栈中的代码执行完毕,主线程就会去读取任务队列,依次执行那些事件所对应的回调函数。
  • 相关阅读:
    php生成xml文件头
    常用正则表达式
    数值数组排序
    《那些年啊,那些事——一个程序员的奋斗史》——97
    《那些年啊,那些事——一个程序员的奋斗史》——98
    《那些年啊,那些事——一个程序员的奋斗史》——99
    《那些年啊,那些事——一个程序员的奋斗史》——100
    《那些年啊,那些事——一个程序员的奋斗史》——100
    《那些年啊,那些事——一个程序员的奋斗史》——99
    《那些年啊,那些事——一个程序员的奋斗史》——98
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/14124565.html
Copyright © 2011-2022 走看看