站长家园(原代码之家)(www.adminjie.com)网站源码,微信源码,游戏源码,商业源码分享平台。
当前位置:网站首页 技术文章 网络编程 正文

JavaScript的单线程你真的理解了吗

时间:2022-01-11 [网络编程]作者:fabuyuan 浏览:4 次

本篇文章给大家带来了我们的JavaScript单线程的相关知识,JavaScript是一门单线程的语言,为什么JavaScript可以一边执行定时器一边执行函数,希望对大家有帮助。

JavaScript的单线程你真的理解了吗  2

1. 进程与线程

1.1 进程(Process)

计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。

我们这里将进程比喻为工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

1.2 线程(thread)

是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

这里把线程比喻一个车间的工人,即一个车间可以允许由多个工人协同完成一个任务。

2. 多线程的浏览器

浏览器内核是多线程,在内核控制下各线程相互配合以保持同步,一个浏览器通常由以下常驻线程组成:

  • GUI 渲染线程

  • JavaScript引擎线程

  • 事件触发线程

  • 定时触发器线程

  • 异步http请求线程

JavaScript的单线程你真的理解了吗  2

我们看到了JS引擎线程,非常的熟悉,没有错,这里是我们执行javascript脚本程序的地方。

而JS引擎是多线程的,单线程是指JS引擎执行JS时只分了一个线程给他执行,意思是JS引擎分配了一个线程给JavaScript执行,也就是我们所说的单线程。

2.1 这里再说下JS的执行机制

由于JavaScript是单线程(一个Tab页内中无论什么时候都只有一个JS线程在运行JavaScript程序)。

所以我们需要依靠任务队列来进行JavaScript代码的执行。

JS引擎会一直等待着任务队列中任务的到来,然后执行任务。

同步任务这么执行当然没问题,我们把任务都放在任务队列里,一个一个执行,逻辑很清晰。但是,如果我们向后台发送请求,发送加接收这段时间可能需要一秒,我们不能等它一秒吧,如果请求五次,那就等五秒?显示不符合我们的需求,所以,我们需要异步任务来处理这个问题。

2.2 同步任务和异步任务

同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务

异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务。

大家肯定对Event Loop有比较具象的认知,这边我不详细说了,不懂可以和我说,我再讲就是了。

3. 本文重重点--可直接看

但是,大家有没有对任务队列抱有疑问?这是个对象?是个数组?按我的逻辑来说,我们JavaScript主线程执行同步函数,异步函数可以放在任务队列里,这个任务队列可以是个对象,当我们执行完同步任务的时候,把这个对象(任务队列)压进主线程中就可以了,但是事实并不我想的这样的。

Evnet Loop的任务队列放在了浏览器的事件触发线程中,当JS引擎执行异步函数的时候,会将异步任务放在事件触发线程中,当对应的异步任务符合触发条件被触发时,事件触发线程会把异步任务添加到JS引擎中的主线程的队尾,等待执行。

是不是和我们想象的JavaScript单线程不太一样?好吧,确实不太一样,所以最后的结论是,我们所说的任务队列竟然是一个线程。

然后,说回我们开头刚开始说过的定时器,大家基本也能猜出来了,它是由定时器线程控制的。

因为JavaScript是单线程的, 如果处于阻塞线程状态就会影响记计时的准确,因此很有必要单独开一个线程用来计时。

当使用setTimeout或setInterval时,它需要定时器线程计时,计时完成后就会将特定的事件推入事件队列中。

4. 结论

所以说,我们说JavaScript是单线程的没错,就是天王老子来了它也是单线程的,但是我们的Event Loop和定时器是放在其他线程中的。

5. V8引擎--扩展

V8引擎是一个JavaScript引擎实现,最初由一些语言方面专家设计,后被谷歌收购,随后谷歌对其进行了开源。

V8使用C++开发,在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能。

有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序。V8支持众多操作系统,如windows、linux、android等,也支持其他硬件架构,如IA32,X64,ARM等,具有很好的可移植和跨平台特性。

5.1 工作流程

V8引擎在执行JavaScript的过程中,主要有两个阶段:编译和运行,与C++的执行前完全编译不同的是,JavaScript需要在用户使用时完成编译和执行。在V8中,JavaScript相关代码并非一下完成编译的,而是在某些代码需要执行时,才会进行编译,这就提高了响应时间,减少了时间开销。在V8引擎中,源代码先被解析器转变为抽象语法树(AST),然后使用JIT编译器的全代码生成器从AST直接生成本地可执行代码。这个过程不同于JAVA先生成字节码或中间表示,减少了AST到字节码的转换时间,提高了代码的执行速度。但由于缺少了转换为字节码这一中间过程,也就减少了优化代码的机会。

V8引擎编译本地代码时使用的主要类如下所示:

  • Script:表示JavaScript代码,即包含源代码,又包含编译之后生成的本地代码,即是编译入口,又是运行入口;

  • Compiler:编译器类,辅组Script类来编译生成代码,调用解释器(Parser)来生成AST和全代码生成器,将AST转变为本地代码;

  • AstNode:抽象语法树节点类,是其他所有节点的基类,包含非常多的子类,后面会针对不同的子类生成不同的本地代码;

  • AstVisitor:抽象语法树的访问者类,主要用来遍历异构的抽象语法树;

  • FullCodeGenerator:AstVisitor类的子类,通过遍历AST来为JavaScript生成本地可执行代码。

JavaScript的单线程你真的理解了吗  2

JavaScript代码编译的过程大致为:Script类调用Compiler类的Compile函数为其生成本地代码。Compile函数先使用Parser类生成AST,再使用FullCodeGenerator类来生成本地代码。本地代码与具体的硬件平台密切相关,FullCodeGenerator使用多个后端来生成与平台相匹配的本地汇编代码。由于FullCodeGenerator通过遍历AST来为每个节点生成相应的汇编代码,缺失了全局视图,节点之间的优化也就无从谈起

【相关推荐:javascript学习教程

以上就是JavaScript的单线程你真的理解了吗的详细内容,更多请关注站长家园其它相关文章!

本文标签:  javascript前端html

转载请注明来源:JavaScript的单线程你真的理解了吗

本文永久链接地址:https://www.adminjie.com/post/7487.html

免责声明:
本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。

附:
二○○二年一月一日《计算机软件保护条例》第十七条规定:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬!鉴于此,也希望大家按此说明研究软件!

版权声明:
一、本站致力于为软件爱好者提供国内外软件开发技术和软件共享,着力为用户提供优资资源。
二、本站提供的部分源码下载文件为网络共享资源,请于下载后的24小时内删除。如需体验更多乐趣,还请支持正版。
三、我站提供用户下载的所有内容均转自互联网。如有内容侵犯您的版权或其他利益的,若有侵犯你的权益请:提交版权证明文件到邮箱 2225329873#qq.com(#换为@) 站长会进行审查之后,情况属实的会在三个工作日内为您删除。

  • 站长家园(原代码之家)会员升级
  • 最新文章
    • mysql怎样in查询操作排序

      mysql怎样in查询操作排序

      在mysql中,可利用“ORDERBY”子句配合SELECT语句in查询来操作排序,语法为“select*from表名where字段值in(排序1,排...

    • docker能用yum命令吗

      docker能用yum命令吗

      docker能用yum命令,docker容器内安装yum的方法:1、通过“apt-getupdate”更新apt-get指令;2、通过“apt-getins...

    • 如何解决docker telnet不通的问题

      如何解决docker telnet不通的问题

      dockertelnet不通的解决办法:1、查看配置文件;2、修改nginx配置文件的端口为80;3、重新加载即可。本文操作环境:centOS6.8系统、Do...

    • css怎样改变一个图片高度和宽度

      css怎样改变一个图片高度和宽度

      在css中,可以使用width和height属性来改变一个图片高度和宽度,只需要给图片元素添加“width:宽度值;height:高度值;”样式即可。width...

    • docker不能删除镜像怎么办

      docker不能删除镜像怎么办

      docker不能删除镜像的解决办法:1、删除REPOSITORY;2、删除IMAGEID;3、通过“dockerimages”查看镜像即可。本文操作环境:c...

    热门文章