• 理解javascript中event loop,


    console.log(1)
        setTimeout(() => console.log(2), 0)
        new Promise((resolve, reject) => {
            console.log(3)
            resolve()
        }).then(() => {
            console.log(4)
        })
    
    //    1 3 4 2

    javaScript

    javascript 是单线程语言,至于其为什么是单线程呢,而不采用多线程。原因就在于,javascipt 是面向用户端的一门语言,其主要作用是与用户交互,渲染数据,操作dom,如果是多线程,就会出现一个问题,比如说,一个线程删除了一个dom节点,另外一个线程添加了一个dom节点,以那个线程为主呢,就会出现混乱的情况。当然,我们可以在操作一个dom之后,加上锁,只允许一个线程操作,但这样,无形之中,程序又平添了复杂程度,未必是一个好的办法。另外,HTML5 中提供了 web worker 等 api,用来处理例如因大量计算而占用主线程的情况,但按照规定,其也受制于主线程,而且不能操作dom。所以,javascript 是一门单线程语言,也只可能是单线程语言.

    任务队列

    为什么会有任务队列呢,还是因为 javascript 单线程的原因,单线程,就意味着一个任务一个任务的执行,执行完当前任务,执行下一个任务,这样也会遇到一个问题,就比如说,要向服务端通信,加载大量数据,如果是同步执行,js 主线程就得等着这个通信完成,然后才能渲染数据,为了高效率的利用cpu, 就有了 同步任务 异步任务 之分。

    - 同步任务,进入主线程,一个一个执行
    - 异步任务, 进入 `event table ` , 注册回调函数 ` callback `, 任务完成之后,
    将 `callback` 移入 `event queue`, 等待主线程调用

    流程图

    任务队列是一中先进先出的数据结构,排在最前面的优先被主线程读取执行,只要当前执行栈一清空,主线程马上会读取任务队列中的第一任务执行。但当遇到定时器时,需要先检查当前时间是否满足定时器需求,满足执行,不满足自动执行下一个

    console.log("主线程开始执行任务")
    const data = {}
    console.log("发现异步任务,执行异步任务,注册回调函数 success 和 fail")
    $.ajax({
        method: 'post',
        url: 'https://localhost:8080/user/new',
        data: data,
        success: res => {
            console.log('异步任务执行完成,服务器响应成功,向event queue 推入 success') 
        },
        fail: err => {
            console.log('异步任务执行,服务器响应失败,向event queue 推入 fail')  
        }
    })
    
    console.log("同步任务执行完成,主线程检查 event queue ")
    console.log("ajax 请求成功响应, 检测到 event queue 中的 success ,执行success")

    上面的代码,我已经对 event loop 有了初步了解,那么接下来梳理一下,同样是异步任务,为何不同类型的异步任务表现却不一样

    setTimeout

        setTimeout(() => {
            console.log("五秒了,我要执行了")
        }, 5000)
    //一般情况下,我们设置一个定时器,如果不去特意的测试,是发现不了,定时器时间并不准确这个问题的,我们做个测试
    
        console.time('timer')
        setTimeout(() => console.timeEnd('timer'), 5000)
        sleep(1000000) // 或者执行一大堆复杂的逻辑
    //我们这个时候发现,输出的时间,并不是 精确的 5000 ,而是根据你后面同步任务执行的时间会有所影响
    
    - 主线程执行console.time('timer'), 开始及时
    // - 执行到setTimeout(), 进入到 `event table` 中并注册回调函数
    // - 开始执行sleep(), sleep 执行的很慢,这个时候,5 秒到了,定时器时间到了之后向
    //   `event queue` 中推送了回调函数,但主线程一直在忙,没有时间去检查 
    //   `event queue`, 一直等到 `sleep()` 执行完成,主线程才检查 `event queue`,
    //   并执行回调函数
    //上述的流程走完,我们知道 setTimeout 这个函数,是经过指定时间后,把要执行的任务加入到 event queue 中,又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着,导致真正的延迟时间远远大于3秒。

    setTimeout(fn, 0)  

    假设主线程并不繁忙,那么 fn 一定就会在 不延迟执行吗,并不会,
    即便主线程为空,0ms 实际上也是达不到的。根据HTML的标准,最低是 4ms。所以不可能做到 0ms

    setInterval 重复执行,每隔多少秒之后,将已经注册好的回调函数推入到event queue中,等待主线程调用

    promise

        console.log(1)
        setTimeout(() => console.log(2), 0)
        new Promise((resolve, reject) => {
            console.log(3)
            resolve()
        }).then(() => {
            console.log(4)
        })
    // 答案应该是 1 3 2 4, 但为什么会是 1 3 4 2 呢,

    这里就要说到 微任务 和 宏任务 了, 除了广义的 同步任务 和 异步任务 之分,对 异步任务 还有更细致的区分,就是 micro Task (微任务) 和 macro Task (宏任务)

    micor Task(微任务) 包括 promise, 当然还有 Node 环境中的,但这里先不梳理

    macro Task(宏任务) 包括 script、setTimeout、setInterval setTimeout和setInterval的回调会推入到宏任务

    不同类型的任务,会进入不同的 event queue, 同是相同类型的任务,进入相同的 event queue, 例如: setTimeout 和 setInterval 会进入相同的 event queue

     测试

    console.log(1)
    
    setTimeout(() => {
        console.log(2)
        new Promise((resolve, reject) => {
            console.log(3)
            resolve()
        }).then(() => {
            console.log(4)
        })
    }, 0)
    
    new Promise((resolve, reject) => {
        console.log(5)
        resolve()
    }).then(() => {
        console.log(6)
    })
    
    setTimeout(() => {
        console.log(7)
        new Promise((resolve, reject) => {
            console.log(8)
            resolve()
        }).then(() => {
            console.log(9)
        })
    }, 0)
    
    console.log(10)

    |

     

  • 相关阅读:
    前端UI框架
    Knowledge
    Microsoft SQL Server
    ASP.NET MVC
    将博客搬至CSDN
    python中的数据类型
    python基础知识
    接口和抽象类的区别
    面向对象的四大特征
    数据结构学习笔记
  • 原文地址:https://www.cnblogs.com/chenzxl/p/14447684.html
Copyright © 2020-2023  润新知