• 技术文章 >web前端 >前端问答

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

    长期闲置长期闲置2022-01-10 19:08:01转载435
    本篇文章给大家带来了我们的JavaScript单线程的相关知识,JavaScript是一门单线程的语言,为什么JavaScript可以一边执行定时器一边执行函数,希望对大家有帮助。

    1. 进程与线程

    1.1 进程(Process)

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

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

    1.2 线程(thread)

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

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

    2. 多线程的浏览器

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

    43.png

    我们看到了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引擎编译本地代码时使用的主要类如下所示:

    44.png

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

    【相关推荐:javascript学习教程

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

    声明:本文转载于:掘金,如有侵犯,请联系admin@php.cn删除
    专题推荐:javascript 前端 html
    上一篇:十分钟搞懂jquery对元素的基本操作 下一篇:html5有哪些特殊标签
    VIP课程(WEB全栈开发)

    相关文章推荐

    • 【腾讯云】年中优惠,「专享618元」优惠券!• 深入浅析JavaScript内置对象(总结分享)• javascript中的style的用法是什么• 聊聊JavaScript中的7种位运算符,看看在实战中如何妙用?• 怎样利用Javascript简单实现星空连线的效果• javascript的case是啥意思
    1/1

    PHP中文网