zoukankan      html  css  js  c++  java
  • js 的单线程与异步

    js的单线程

    从我们第一天接触js的时候我们就知道js是单线程的,且js是异步的,首先来看一下基本概念

    什么是线程

    线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。(百度百科)

    举个最简单的例子 , 在我们电脑的任务管理器中你打开一个应用程序的时候 就会多一个进程,他代表了cpu能处理的单个任务。

    线程是进程下的执行者,一个进程至少会开启一个线程(主线程),也可以开启多个线程,比如你打开了一个vscode编辑器,里边你能做的操作会有很多比如cmd node 等等

    浏览器的进程

    js是运行在浏览器的,是由js引擎解析和执行的,那么我们先了解一下浏览器都有哪些线程
    首先要说明的是 浏览器是多线程的

    • Browser进程:浏览器的主进程

    • 第三方插件进程

    • GPU进程

    • 浏览器渲染进程

    对于前端来讲这些进程中最重要的是浏览器渲染进程,也被称之为是浏览器内核,因为我们的页面渲染,事件等等都在这个进程中进行的

    浏览器的渲染进程里边有一些常驻的线程比如说

    GUI渲染线程
    • 负责解析html css 构建dom树 编译 RenderObject树,计算布局渲染等等
    • 在页面重回或者dom回流的时候这个线程就会被执行
    • 页面在第一次渲染的时候肯定会触发这个线程
    Js引擎线程
    • 主要负责处理javascript的脚本
    • 也称之为js内核,一个tab页中只有一个js线程在运行js程序

    需要注意的是Gui渲染线程和js引擎线程是冲突的,他们不能同时执行

    所以说如果我们页面在一开始js文件需要计算或者操作的时间比较长的时候,会出现大段时间的白屏,
    因为js引擎在执行的时候会使页面渲染堵塞,如果dom发生更新的时候,gui更新会被存在一个队列里边,等到js引擎空闲的时候才会被执行

    一个tab页里边无论如何都只有一个js线程,就算是后来的webworker ,他也是只属于js引擎的一个子类,并且它不能操作dom

    事件触发线程
    • 常用的事件有很多比如点击事件 ajax请求事件等等他们会在对应的条件触发的时候被添加到事件线程中
    • 这些事件会在js引擎空闲的时候去执行
    定时触发器线程
    • 定时器与计时器的线程,在满足条件之后会被添加到事件队列里边,等待js引擎空闲的时候去执行
    http请求
    • 在发送http请求的时候,这个线程会被执行
    • 再有回调函数的时候,这个线程会把回调的事件放入到事件队列中去,等待js引擎执行

    突然觉得js引擎好累,什么都是要他去做,为什么不设计成多线程,从网上其他地方看了的答案,大同小异,讲的是多线程操作dom有可能会同时操作一个dom发生错误云云

    说完了上边的一些概念,你也应该大体的了解了js的单线程这个问题
    下边从js引擎的一些运行机制说一说js的异步

    刚才已经讲了,浏览器中不仅有js引擎线程还有其他,异步的话主要会用到事件触发线程和定是触发器线程的概念

    在js中氛围同步任务和异步任务 ,所有的同步任务都会在主线程上执行,形成一个执行栈(先进后出)
    在主线程之外还有一个异步的事件队列
    在执行栈执行完毕之后,也就是同步任务执行完毕之后,js引擎线程就会去轮询事件队列,看有没有需要执行的事件,有的话就会执行事件队列的事件

    我记得我最开始的时候使用ajax 或者数据库查询的时候遇到过这么一个情况,在做完操作之后就天真的认为可以用返回的值,结果当时我被异步搞得里焦外嫩,甚至我以为在发送完请求之后多做一些操作等一会请求,请求值就会返回来,结果。。。

    其实不然, 在同一个事件循环内部,无论做多少操作,你的异步操作只会在执行栈执行完毕之后才会被执行

    同时异步也是有优先级的,在事件循环里边js的任务类型分为两种

    • 宏任务
    • 微任务

    宏任务就是说执行栈里的每一个被执行的代码就是一个宏任务,包括一个事件产生的回调执行
    宏任务会在执行完毕一段代码之后先对dom进行一次渲染,然后再执行下一个宏任务

    微任务是再宏任务执行完毕之后立即执行的,他在dom重新渲染之前,
    所以微任务的相应速度比宏任务是要快的

    像 定时器,延时器 主代码块等等就是一个宏任务,promise nextTick等就是微任务
    正常在延时器打印和在promise里边打印,promise的打印是会比延时器的先打印的

    所以总结一下js的运行机制是

    • 执行栈执行宏任务
    • 执行栈没有任务就去轮询事件队列
    • 如果执行期间遇到微任务,就添加到微任务队列
    • 一个宏任务执行完毕后会立即执行当前微任务队列的任务
    • 宏任务执行完毕后开始渲染
    • 然后开启下一轮宏任务

    以上有说的不对或者不足之处,请批评指正

  • 相关阅读:
    在Delphi中使用indy SMTP发送gmail邮件[转]
    Delphi APP 開發入門(四)簡易手電筒
    Delphi APP 開發入門(六)Object Pascal 語法初探
    Delphi APP 開發入門(五)GPS 定位功能
    Delphi APP 開發入門(十)REST Client 開發
    Delphi APP 開發入門(九)拍照與分享
    各种电平的理解
    串口调试
    DSP中-stack和-heap的作用
    不同深度的图片转换cvConvertScale
  • 原文地址:https://www.cnblogs.com/netUserAdd/p/10930067.html
Copyright © 2011-2022 走看看