• JavaScript学习-JavaScript 如何工作:对引擎、运行时、调用堆栈的概述


      随着JavaScript越来越流行,越来越多的团队广泛的把JavaScript应用到前端、后台、hybrid 应用、嵌入式等等领域。

      这篇文章旨在深入挖掘JavaScript,以及向大家解释JavaScript是如何工作的。我们通过了解它的底层构建以及它是怎么发挥作用的,可以帮助我们写出更好的代码与应用。据 GitHut 统计显示,JavaScript 长期占据GitHub中 Active RepositoriesTotal Pushes 的榜首,并且在其他的类别中也不会落后太多。

      如果一个项目越来越依赖 JavaScript,这就意味着开发人员必须利用这些语言和生态系统提供更深层次的核心内容去构建一个令人振奋的应用。然而,事实证明,有很多的开发者每天都在使用 JavaScript,但是却不知道在底层 JavaScript 是怎么运作的。

     
     
    一、概述
      几乎每个人都听说过 V8 引擎的概念,而且,大熟人都知道 JavaScript 是单线程的,或者是它是使用回调队列的。
      
      在这篇文章中,我们将详细的介绍这些概念,并解释 JavaScript 是怎么工作的。通过了解这些细节,你就能利用这些提供的 API 来写出更好的,非阻塞的应用来。如果你对 JavaScript 比较陌生,那么这篇文章将帮助您理解为什么 JavaScript 相较于其他语言显得如此“怪异”。如果您是一位经验丰富的 JavaScript 开发人员,希望它能给你带来一些新的见解,说明 JavaScript 的运行时,尽管你可能每天都会用到它。

    二、JavaScript引擎
      JavaScript引擎最流行的当然是 V8 的引擎了,V8 引擎使用 Chrome 以及 Node 中,下面有个简单的图能说明他们之间的关系。

       这个引擎主要是由两部分组成:

      (1)内存堆:这是内存分配发生的地方

      (2)调用栈:这是你的代码执行的地方

    三、运行时

      有些浏览器的 API 经常被使用到(比如说:setTimeout),但是,这些 API 都不是引擎提供的。那么,他们是哪里来的呢?事实上。这里的情况有点复杂。

       所以说,我们还有很多引擎之外的 API ,我们把这些称为浏览器提供的 Web API ,比如说 DOM ,AJAX,setTimeout 等。

      然后我们还拥有如此流行的事件循环和回调队列。

    四、调用栈

      JavaScript 是一门单线程的语言,这意味着它只有一个调用栈,因此,它同一时间只能做一件事。

      调用栈是一种数据结构,他记录了我们在程序中的位置,如果我们运行到一个函数,它将会将其放置到栈顶。当这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。

      如下例子:

        function multiply(x, y) {
          return x * y;
        }
        function printSquare(x) {
          var s = multiply(x, x);
          console.log(s);
        }
        printSquare(5);

      当程序开始执行的时候,调用栈是空的,然后,步骤如下:

       每一个进入调用栈的都称为 “调用帧”。

      这能清楚的知道当异常发生的时候堆栈追踪是怎么被构造的,堆栈的状态是如何的。让我们看一下下面的代码。

        function foo() {
          throw new Error('SessionStack will help you resolve crashes :)');
        }
        function bar() {
          foo();
        }
        function start() {
          bar();
        }
        start();

      如果这发生在 Chrome 里(假设这段代码在一个名为foo.js的文件中),那么将会发生一下的堆栈追踪。

       “堆栈溢出”,当你到达调用栈最大的大小的时候,就会发生这种情况,而且这相当容易发生,特别是你写递归的时候却没有全方面的测试它。我们来看看下面的代码:

        function foo() {
          foo();
        }
        foo();

      当我们的引擎开始执行这段代码的时候,它从foo 函数开始,然后这是个递归的函数,并且在没有任何的终止条件下开始调用自己,因此每执行一步,就会把这个相同的函数一次又一次的添加到调用堆栈中,然后他看起来是这样的:

       然后,在某一个时刻,调用栈中的函数调用的数量超过了调用栈的实际大小,浏览器就决定干掉它,抛出一个错误,它看起来就像是这样:

       在单个线程上运行代码很容易,因为你不必处理在多线程中出现的复杂场景——例如死锁,但是在一个线程上运行也是非常有限制。由于 JavaScript 只有一个堆栈,当某段代码运行变慢的时候会发生什么?


    作者:小烜同学
    链接:https://juejin.cn/post/6844903510538993671
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    slf4j日志框架绑定机制
    Btrace使用入门
    JVM反调调用优化,导致发生大量异常时log4j2线程阻塞
    [转载]Javassist 使用指南(三)
    [转载]Javassist 使用指南(二)
    [转载]Javassist 使用指南(一)
    数组升序排序的方法Arrays.sort();的应用
    copyOfRange的应用
    copyOf数组复制方法的使用(数组扩容练习)
    binarySearch(int[] a,int fromIndex,int toIndex, int key)的用法
  • 原文地址:https://www.cnblogs.com/zhilili/p/14794855.html
Copyright © 2020-2023  润新知