zoukankan      html  css  js  c++  java
  • Event Loop详解

    1.进程,单线程与多线
    • 进程: 运行的程序就是一个进程,比如你正在运行的浏览器,它会有一个进程。
    • 线程: 程序中独立运行的代码段。
    • 一个进程由单个或多个线程组成,线程是负责执行代码的。
    2.单线程与多线程的区别
    • 单线程 从头执行到尾,一行一行执行,如果其中一行代码报错,那么剩下代码将不再执行。同时容易代码阻塞。
    • 多线程 代码运行的环境不同,各线程独立,互不影响,避免阻塞。
    任务队列

    任务分两种:

    一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

    • 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
    • 异步任务指的是,不进入主线程、而进入"任务队列"(taskqueue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行

    "任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。但是,由于存在后文提到的"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程

    Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个。那么什么任务,会分到哪个队列呢?

    • 宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.

    • 微任务:process.nextTick, Promise, Object.observer, MutationObserver.
      我们上面讲到,当stack空的时候,就会从任务队列中,取任务来执行。共分3步:

    • 取一个宏任务来执行。执行完毕后,下一步。

    • 取一个微任务来执行,执行完毕后,再取一个微任务来执行。直到微任务队列为空,执行下一步。

    • 更新UI渲染。

    Event Loop 会无限循环执行上面3步,这就是Event Loop的主要控制逻辑。其中,第3步(更新UI渲染)会根据浏览器的逻辑,决定要不要马上执行更新。毕竟更新UI成本大,所以,一般都会比较长的时间间隔,执行一次更新。

    3. Event Loop(浏览器)

    js既然是单线程,那么肯定是排队执行代码,那么怎么去排这个队,就是Event Loop。虽然JS是单线程,但浏览器不是单线程。浏览器中分为以下几个线程:

    • js线程
    • UI线程
    • 事件线程(onclick,onchange,...)
    • 定时器线程(setTimeout, setInterval)
    • 异步http线程(ajax)

    其中JS线程和UI线程相互互斥,也就是说,当UI线程在渲染的时候,JS线程会挂起,等待UI线程完成,再执行JS线程.

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

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

    在进程启动时,node便会创建一个类似while(true)的循环,每执行一次循环体的过程我们称为tick,每个tick的过程就是查看是否是否有事件等待处理,如果有,就取出事件及其相关的回调函数。如果有关联的回调函数,就执行他们,然后进入有下一个循环体

    4.异步的事件

    process.nextTick()
    • 性能上来说很轻量,时间复杂的O(1)
    • 回调函数保存在数组中,在一轮循环中数组中的回调函数全部执行完
    setImmediate()
    • 和上面一样都是将回调函数延迟执行,不同上面的优先级别要高,原因是事件循环对观察者的检查是有先后顺序的,process.nextTick()属于idle观察者,setImmediat属于check观察者。在每一轮循环中,idle先与I/O观察者,I/观察者先于check观察者。
    • 回调函数存在链表中,每一次循环只执行链表中的一个回调函数
      时间复杂度lg(n)
    定时器setTimeout()/setInterval()
    • 调用时会创建定时器会被插入到定时器观察者内部的一个红黑树中,每次tick时,会取出定时器,检查是否超时,如果超时,就形成一个事件,执行回调函数。问题就是时间不一定精确
    • 时间复杂度lg(n)
  • 相关阅读:
    linux解压缩各种命令
    memset
    STRUCT_OFFSET( s, m )宏
    请问这个宏是什么意思 #define NOTUSED(v) ((void) v)?
    typedef特殊用法:typedef void* (*fun)(void*)
    localtime、localtime_s、localtime_r的使用
    Git使用(一)
    【转】linux gcc _attribute__((weak)) 简介及作用
    我的技术博客
    .net 4.0(2.0)“检测到有潜在危险的 Request.Form 值”的解决方法
  • 原文地址:https://www.cnblogs.com/chenjinxinlove/p/8467802.html
Copyright © 2011-2022 走看看