• [转]Event Loop(事件循环)机制


    转自:https://www.jianshu.com/p/6e9f4eb7fdbb

    在讲 Event Loop (事件循环)之前,我们来了解点 node 的东西,来帮助我们更加明白事件循环是干什么的

    Node 是什么

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,Node 不是一门语言,是让 js 运行在后端的,运行时不包括 js 全集,因为在服务端中不包含 DOM 和 BOM,Node 也提供了一些新的模块,比如 http,fs等模块。

    Node 解决了什么

    Node 的首要目标是提供一种简单的,用于创建高性能服务器的开发工具
    Web 服务器的瓶颈在于并发的用户量,对比 Java 和 Php 的实现方式

    Node在处理高并发,I/O 密集场景有明显的性能优势
    • 高并发,是指在同一时间并发访问服务器
    • I/O 密集指的是文件操作、网络操作、数据库,相对的有 CPU 密集,CPU 密集指的是逻辑处理运算、压缩、解压、加密、解密

    Web 主要场景就是接收客户端的请求读取静态资源和渲染界面,所以 Node 非常适合 Web 应用的开发。

    进程与线程

    进程是操作系统分配资源和调度任务的基本单位,线程是建立在进程上的一次程序运行单位,一个进程上可以有多个线程。

    1. 浏览器线程
      • 用户界面-包括地址栏、前进/后退按钮、书签菜单等
      • 浏览器引擎-在用户界面和呈现引擎之间传送指令(浏览器的主进程)
      • 渲染引擎,也被称为浏览器内核(浏览器渲染进程)
      • 一个插件对应一个进程(第三方插件进程)
      • GPU提高网页浏览的体验( GPU 进程)
    2. 浏览器渲染引擎
      • 渲染引擎内部是多线程的,内部包含 ui 线程和 js 线程
      • js 线程 ui 线程 这两个线程互斥的,目的就是为了保证不产生冲突。
      • ui 线程会把更改的放到队列中,当 js 线程空闲下来的时候,ui 线程在继续渲染
    3. js 单线程
      • js 是单线程,为什么呢?如果多个线程同时操作 DOM ,哪页面不会很混乱?这里所谓的单线程指的是主线程是单线程的,所以在 Node 中主线程依旧是单线程的。
    4. webworker 多线程
      • 它和 js 主线程不是平级的,主线程可以控制 webworker,但是 webworker不能操作 DOM,不能获取 document,window
    5. 其他线程
      • 浏览器事件触发线程(用来控制事件循环,存放 setTimeout、浏览器事件、ajax 的回调函数)
      • 定时触发器线程(setTimeout 定时器所在线程)
      • 异步 HTTP 请求线程(ajax 请求线程)

    单线程特点是节约了内存,并且不需要在切换执行上下文。而且单线程不需要管锁的问题,所谓 锁,在 java 里才有锁的概念,所以我们不用细研究

    浏览器中的 Event Loop

     
    2.jpg
    • 同步任务都在主线程上执行,形成一个执行栈
    • 主线程之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列之中放置一个事件。
    • 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,将队列中的事件放到执行栈中依次执行
    • 主线程从任务队列中读取事件,这个过程是循环不断的

    整个的这种运行机制又称为 Event Loop (事件循环)

    node 中的 Event Loop

    如图(图片是借鉴的):


     
    3.jpg

    * 我们写的代码会交给 V8 引擎去进行处理
    * 代码中可能会调用 nodeApi,node 会交给 LIBUV 库处理
    * LIBUV 通过阻塞 i/o 和多线程实现了异步 io
    * 通过事件驱动的方式,将结果放到事件队列中,最终交给我们的应用。

    同步,异步 阻塞和非阻塞

    • 阻塞和非阻塞指的是调用者的状态,关注的是程序在等待调用结果时的状态
    • 同步和异步指的是被调用者是如何通知的,关注的是消息通知机制

    宏任务和微任务

    • macro-task(宏任务):
      • setTimeout, setInterval, setImmediate, I/O
    • micro-task(微任务):
      • process.nextTick,
      • 原生 Promise (有些实现的promise 将 then 方法放到了宏任务中,浏览器默认放到了微任务),
      • Object.observe (已废弃),
      • MutationObserver(不兼容,已废弃)
      • MessageChannel(vue中 nextClick 实现原理)

    同步代码先执行,执行是在栈中执行的,微任务大于宏任务,微任务会先执行(栈),宏任务后执行(队列)

    讲到这里,敲几行代码来总结下我们上面讲到的知识点把

    《1》宏任务,微任务在浏览器和 node 环境执行顺序不同

    // 这个列子里面,包含了宏任务,微任务,分别看看浏览器和node 打印的结果
    console.log(1)
    // 栈
    setTimeout(function(){
        console.log(2)
        // 微任务
        Promise.resolve(100).then(function(){
            console.log('promise')
        })
    })
    // 栈
    let promise = new Promise(function(resolve, reject){
        console.log(7)
        resolve(100)
    }).then(function(data){
        // 微任务
        console.log(data)
    })
    // 栈
    setTimeout(function(){
        console.log(3)
    })
    console.log(5)
    // 浏览器结果:1 7 5 100 2 promise 3
    // node 结果:  1 7 5 100 2 3 promise
    

    浏览器和 node 环境执行顺序不同,浏览器是先把一个栈以及栈中的微任务走完,才会走下一个栈。node 环境里面是把所以栈走完,才走微任务

    《2》setTimeout setImmediate 都是宏任务,谁优先执行呢?

    setTimeout(function(){
        console.log('timeout')
    })
    setImmediate(function(){
        console.log('setImmediate')
    })
    // 结果打印:timeout setImmediate
    

    setTimeout setImmediate 这两个取决于 node 的执行时间

    《3》nextTick 和 then 都属于微任务,谁优先执行呢?

    process.nextTick(function(){
        console.log('nextTick')
    })
    Promise.resolve().then(function(){
        console.log('then')
    })
    // 结果打印:nextTick then
    
    // 再加一个宏任务呢
    setImmediate(function(){
        console.log('setImmediate')
    })
    // 结果打印:nextTick  then  setImmediate
    

    nextTick 会比 其他微任务、宏任务执行快

    《4》i/o 文件操作(宏任务),搭配微任务,谁优先执行呢?

    let fs = require('fs');
    fs.readFile('./1/log',function(){
        console.log('fs')
    })
    process.nextTick(function(){
        console.log('text')
    })
    // 结果打印:text  fs
    

    i/o 文件操作(宏任务), 如果有微任务,先执行微任务,在执行文件读取



    作者:alipy_258
    链接:https://www.jianshu.com/p/6e9f4eb7fdbb
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    echart------属性详细介绍
    网页链接(插件,判断服务)
    简单的轮播效果
    实时时间
    Oracle Partition By 的使用
    Java配置----JDK开发环境搭建及环境变量配置
    流程控制语句以及引号的使用
    解决报表表头格式问题
    k3could报表中替换最后行汇总字段方法
    k3cloud中使用委托添加提示对话框点击确定后执行方法
  • 原文地址:https://www.cnblogs.com/sugar-tomato/p/13030769.html
Copyright © 2020-2023  润新知