JavaScript 对引擎、运行时、调用堆栈的概述理解

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

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

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

概述

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

JavaScript 引擎

JavaScript 引擎说起来最流行的当然是谷歌的 V8 引擎了, V8 引擎使用在 Chrome 以及 Node 中,下面有个简单的图能说明他们的关系:

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

  • 内存堆:这是内存分配发生的地方
  • 调用栈:这是你的代码执行时的地方

运行时

有些浏览器的 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 只有一个调用堆栈,当某段代码运行变慢时会发生什么?

并发与事件循环

调用栈中的函数调用需要大量的时间来处理,那么这会发生什么情况呢?例如,假设你想在浏览器中使用 JavaScript 进行一些复杂的图片转码。

你可能会问?这算什么问题?事实上,问题是当调用栈有函数要执行,浏览器就不能做任何事,它会被堵塞住。这意味着浏览器不能渲染,不能运行其他的代码,它被卡住了。如果你想在应用里让 UI 很流畅的话,这就会产生问题。

而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。大多数浏览器都会这么做,报一个错误,询问你是否想终止 web 页面。

总结

以上所述是小编给大家介绍的JavaScript 对引擎、运行时、调用堆栈的概述理解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • JavaScript基于数组实现的栈与队列操作示例

    本文实例讲述了JavaScript基于数组实现的栈与队列操作.分享给大家供大家参考,具体如下: 栈数据结构: 1. 后进先出 队列在列表的尾端添加项,从列表的尾端移除项 队列图: 实现代码: var colors = ["red","blue"]; colors.push("brown"); //从队列尾部添加一项 console.log(colors);//[ 'red', 'blue', 'brown' ] var item =colors.

  • JS中数据结构之栈

    栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快,而且容易实现. 栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶.栈被称为一种后入先出(LIFO,last-in-first-out)的数据结构.由于栈具有后入先出的特点,所以任何不在栈顶的元素都无法访问.为了得到栈底的元 素,必须先拿掉上面的元素. 栈的实现 用数组 dataStore 保存栈内元素,构造函数将其初始化为一个空数组.变量 top 记录 栈顶位置,被构造函数初始化为 0,表示栈顶对应数组

  • 深入理解JavaScript 中的执行上下文和执行栈

    如果你是或者想成为一名 JavaScript 开发者,你必须知道 JavaScript 程序内部是如何执行的.理解执行上下文和执行栈对于理解其他 JavaScript 概念(如变量声明提升,作用域和闭包)至关重要. 正确理解执行上下文和执行栈的概念将使您成为更出色的 JavaScript 开发者. 闲话少说,让我们开始吧 :) 分享自 Bit的博客 使用 Bit 应用所提供的组件作为构建模块,你就是架构师.随时随地和你的团队分享.发现和开发组件,快来尝试鲜! Bit - 分享和创造代码组件: B

  • JavaScript栈和队列相关操作与实现方法详解

    本文实例讲述了JavaScript栈和队列相关操作与实现方法.分享给大家供大家参考,具体如下: 一.栈的介绍 栈就是和列表类似的一种数据结构,数据只能在栈顶添加或者删除.栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,成为栈顶.栈具有后进先出的特点,所以任何不在栈顶的元素都无法访问. 后进先出(LIFO,last-in-first-out)的数据结构. 对栈的操作 1.对栈的两种主要操作为将一个元素压入栈和将一个元素弹出栈. 入栈:push(); 出栈:pop(); 2.预览栈顶的元素pe

  • nodejs超出最大的调用栈错误问题

    今天早上老大和我说之前项目里面的那个数据要改动,要对 mongodb 中每条记录进行 update 操作,你写个脚本跑一下吧. 然后,我默默的回到电脑前,努力工作的一天又开始了.由于此表数据量有点略大,该有一千多万条记录.所以考虑使用 mongodb 的 cursor 游标来进行遍历修改. 程序实现的代码大致如下 function modify(cursor) { cursor.hasNext(function(err,bool) { if(err) { return console.log(e

  • JS的函数调用栈stack size的计算方法

    如果你写了一个一直调用自身的死循环,那么恭喜你,很快就可以看到报错:Uncaught RangeError: Maximum call stack size exceeded.那么这个call stack size有多少呢? 1. 计算方法 如下的方法可以为你计算出你使用的JavaScript引擎可以支持多深的调用(由Ben Alman的一段代码获得灵感): function computeMaxCallStackSize() { try { return 1 + computeMaxCallS

  • JavaScript数据结构之栈实例用法

    栈 先来看一道题 Leetcode 32 Longest Valid Parentheses (最长有效括号) 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度. 示例 1: 输入: "(()" 输出: 2 解释: 最长有效括号子串为 "()" 示例 2: 输入: ")()())" 输出: 4 解释: 最长有效括号子串为 "()()" 这道题可以用动态规划来做,也能用简洁明了的栈来解决. 什么是

  • JavaScript 对引擎、运行时、调用堆栈的概述理解

     随着JavaScript越来越流行,越来越多的团队广泛的把JavaScript应用到前端.后台.hybrid 应用.嵌入式等等领域. 这篇文章旨在深入挖掘JavaScript,以及向大家解释JavaScript是如何工作的.我们通过了解它的底层构建以及它是怎么发挥作用的,可以帮助我们写出更好的代码与应用.据 GitHut 统计显示,JavaScript 长期占据GitHub中 Active Repositories 和 Total Pushes 的榜首,并且在其他的类别中也不会落后太多. 如果

  • JavaScript调用堆栈及setTimeout使用方法深入剖析

    Javascript中会经常用到setTimeout来推迟一个函数的执行,如: 复制代码 代码如下: setTimeout(function(){alert("Hello World");},1000); 会在执行到这句话后延迟1秒钟来弹出alert窗口.那么再看这一段: 复制代码 代码如下: function a(){ setTimeout(function() {alert(1)}, 0); alert(2); } a(); 注意这段代码中的setTimeout延迟设为了0,就是延

  • 详解JavaScript中的执行上下文及调用堆栈

    一.执行上下文是什么 代码运行是在一定的环境之中运行的,这个运行环境我们就成为执行环境,也就是执行上下文,按照执行环境不同,我们可以分为三类: 全局执行环境:代码首次执行时候的默认环境 函数执行环境:每当执行流程进入到一个函数体内部的时候 Eval执行环境:当eval函数内部的文本执行的时候 二.执行上下文栈是什么 既然是'栈',那就得符合'栈'的特性,即数据结构是先进后出.下面我们看一段代码: function cat(a){ if(a<0){ return false; } console.

  • 详解Java虚拟机(JVM)运行时

    JVM(Java虚拟机)是一个抽象的计算模型.就如同一台真实的机器,它有自己的指令集和执行引擎,可以在运行时操控内存区域.目的是为构建在其上运行的应用程序提供一个运行环境.JVM可以解读指令代码并与底层进行交互:包括操作系统平台和执行指令并管理资源的硬件体系结构.本文主要介绍Java虚拟机(JVM)运行时详解. 我们知道的JVM内存区域有:堆和栈,这是一种泛的分法,也是按运行时区域的一种分法,堆是所有线程共享的一块区域,而栈是线程隔离的,每个线程互不共享. 线程不共享区域 每个线程的数据区域包括

  • 详解Javascript函数声明与递归调用

    Javascript的函数的声明方式和调用方式已经是令人厌倦的老生常谈了,但有些东西就是这样的,你来说一遍然后我再说一遍.每次看到书上或博客里写的Javascript函数有四种调用方式,我就会想起孔乙己:茴字有四种写法,你造吗? 尽管缺陷有一堆,但Javascript还是令人着迷的.Javascript众多优美的特性的核心,是作为顶级对象(first-class objects)的函数.函数就像其他普通对象一样被创建.被分配给变量.作为参数被传递.作为返回值以及持有属性和方法.函数作为顶级对象,

  • 探究Javascript模板引擎mustache.js使用方法

    我们将为大家详解Mustache.js轻量级JavaScript模版引擎使用方法. 简单示例 function show(t) { $("#content").html(t); } var view = { title: 'YZF', cacl: function () { return 6 + 4; } }; $("#content").html(Mustache.render("{{title}} spends {{cacl}}", view

  • javascript模版引擎-tmpl的bug修复与性能优化分析

    精妙的 tmpl 前端模板类开源的不少,但最属 jQuery 作者 John Resig 开发的 "javascript micro templating" 最为精妙,寥寥几笔便实现了模板引擎核心功能. 它的介绍与使用方式请看作者博客:http://ejohn.org/blog/javascript-micro-templating/ 让我们先看看他的源码: 复制代码 代码如下: (function(){ var cache = {}; this.tmpl = function (st

  • JavaScript模板引擎用法实例

    本文实例讲述了JavaScript模板引擎用法.分享给大家供大家参考.具体如下: 这里介绍的这个模板引擎写得短小精悍,非常值得一看 tmpl.js文件如下: // Simple JavaScript Templating // John Resig - http://ejohn.org/ - MIT Licensed (function() { var cache = {}; this.tmpl = function tmpl(str, data) { // Figure out if we'r

  • JavaScript模板引擎实现原理实例详解

    本文实例讲述了JavaScript模板引擎实现原理.分享给大家供大家参考,具体如下: 1.入门实例 首先我们来看一个简单模板: <script type="template" id="template"> <h2> <a href="{{href}}" rel="external nofollow" > {{title}} </a> </h2> <img src

  • 修改Tomcat运行时jvm编码问题

    问题: 最近在部署项目的时候出现数据乱码的情况,经过一番查看项目都是用的UTF-8编码格式,数据也是,但是经过调用接口传给对方就乱码了. 由于是部署在Windows环境下,Windows默认编码GBK,这就导致了jvm运行时编码不一致的问题,修改也很容易. 解决办法: Linux环境下如果使用的UTF-8编码,可以不用修改,因为Linux默认为UTF-8 war包部署在Tomcat 修改jvm编码 Linux环境 在catalina.sh配置 JAVA_OPTS="$JAVA_OPTS -Dfi

随机推荐