JavaScript是如何工作的:引擎,运行时间以及调用栈的概述
JavaScript是如何工作的:引擎,运行时以及调用栈的概述
原文:How JavaScript works: an overview of the engine, the runtime, and the call stack
译者:neal1991
welcome to star my articles-translator, providing you advanced articles translation. Any suggestion, please issue or contact me
LICENSE: MIT
随着JavaScript变得越来越流行,团队在多个层级都对它进行利用-前端,后端,混合应用,嵌入式设备以及更多。
正如GitHut stats所展示的那样,JavaScript是Github上面最活跃以及总Push次数最多的语言。在其它类别中也不会落后太多。
(获取最新的 GitHub language stats).
如果项目对于JavaScript越来越依赖,这意味着为了构建好的软件开发者必须利用这个JS提供的一切并且对于生态系统的内部有着更深的理解。
因此,尽管每天有很多开发者在使用JavaScript,但并不知道内部到底发生了什么。
概览
几乎每个人都已经听说过V8引擎的概念,并且很多知道JavaScript是单线程的或者它是使用一个回调队列的。
在这篇博文中,我们将会详细讲述所有概念并且解释JavaScript是如何真正运行的。在了解这些细节之后,你将能够写出能够适宜地利用提供的API的更好的,非阻塞的app。
如果对于JvaScript来说还不是很了解,这篇博文将会帮助你理解为什么JavaScript和别的语言相比如此“奇怪”。
如果你是一个有经验的JavaScript开发者,希望这篇文章能够让你对你每天使用的JavaScript Runtime是如何真正工作的。
JavaScript 引擎
最流行的JavaScript引擎的例子之一就是谷歌的V8引擎。比如Chrome以及Node.js内部就是使用V8引擎。下面是一个简单的视图示例:
引擎主要由两个部分组成:
- 内存堆——这是内存分配发生的地方
- 回调——这是你代码执行时的栈帧。
Runtime
有很多浏览器中的API几乎都被JavaScript开发者使用过(比如:’setTimeout’)。然而这些API并不是由引擎提供的。
那么,它们是从哪来的呢?
事实证明这有一点复杂。
因此,虽然我们有引擎但实际上是有更多。我们有那些由浏览器提供的Web API,像DOM, AJAX, setTimeout以及更多。
接着,我们还有非常流行的事件循环(event loo)以及回调队列(callback queue)。
调用栈
JavaScript是一种单线程的编程语言,这意味着它只拥有一个单独的调用栈。因此它一次只能做一件事情。
调用栈是一种数据结构记录着我们正在程序的什么地方。如果我们步入一个函数,我们就将这个函数放在栈的顶部。如果我们从一个函数返回,我们则是将这个函数从栈顶弹出。这就是这个栈所做的一切。
让我们看一个例子。参看如下代码:
function multiply(x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);
当引擎执行这段代码的时候,调用栈首先将会是空的。然后,将会按照以下步骤进行:
调用栈中的每一项都被称为栈帧(Stack Frame)。
并且这正是都异常被抛出的时候栈追踪是如何构建的——这基本就是异常发生时调用栈的状态。请看如下代码:
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来做一些复杂的图像转换。
你可能会问——为什么这也会是一个问题?问题是尽管调用栈具有函数来执行,但是浏览器实施中不能做任何其他的事——它被阻塞了。这意味着浏览器不能渲染,它不能运行其他的代码,它就是歇菜了。如果你希望你的app能够具有流畅的UI的时候就会产生问题。
并且这不是唯一的问题。一旦你的浏览器开始处理调用栈中的大量任务,他将在很长时间内都无法响应。大多数浏览器通过抛出错误来采取行动,询问你是否想中止网页。
现在,这并不是一种最好的用户体验,是不是?
因此,我们如何在不阻塞UI并且让浏览器保持响应的情况下执行大量的代码?解决方案就是异步回调。
这个将会在”JavaScript是如何工作的”的第二部分进一步解释。
同时,如果你很难在你的JavaScript重现并且理解问题的时候,可以看看 SessionStack。SessionStack记录了你的web应用中的一切:所有的DOM变化,用户交互,JavaScript异常,栈追踪,失败的网络请求以及调试消息。
使用SessionStack,你可以重现你的web应用中的问题就像录像一样,并且可以看到用户交互的一切。
现在有一个免费的计划能够允许你可以开始免费试用
可以扫描二维码或者搜索 mad_coder 关注微信公众号,点击阅读原文可以获取链接版原文。
JavaScript是如何工作的:引擎,运行时间以及调用栈的概述的更多相关文章
- JavaScript是如何工作的:引擎,运行时和调用堆栈的概述!
摘要: 理解JS执行原理. 原文:JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 本文是旨在深入研究JavaScrip ...
- JavaScript是如何工作的01:引擎,运行时和调用堆栈的概述!
概述 几乎每个人都已经听说过 V8 引擎,大多数人都知道 JavaScript 是单线程的,或者它使用的是回调队列. 在本文中,我们将详细介绍这些概念,并解释 JavaScrip 实际如何运行.通过了 ...
- 浏览器-09 javascript引擎和Chromium网络栈
语言的运行 C/C++语言 使用编译器直接将它们编译成本地代码(机器指令),这是由开发人员在代码编写完成之后实施; 用户只是使用这些编译好的本地代码,这些本地代码被系统的加载器加载执行,由操作系统调度 ...
- JavaScript 是如何工作的:JavaScript 的共享传递和按值传递
摘要: 原始数据类型和引用数据类型的副本作为参数传递给函数. 原文:JavaScript 是如何工作的:JavaScript 的共享传递和按值传递 作者:前端小智 Fundebug经授权转载,版权归原 ...
- JavaScript 是如何工作的:JavaScript 的内存模型
摘要: 从内存角度理解 let 和 const 的意义. 原文:JavaScript 是如何工作的:JavaScript 的内存模型 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这 ...
- JavaScript是如何工作的:编写自己的Web开发框架 + React及其虚拟DOM原理
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 19 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- JavaScript是如何工作的:深入类和继承内部原理 + Babel和TypeScript 之间转换
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 15 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能
摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...
随机推荐
- eclipse设置代码上屏按键
摘要 eclipse默认设置下,当自动补全代码框弹出时,我们按下"."."空格"."Enter"."tab",被选中的代 ...
- es6新的数据类型——generator
todo 一.Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同. 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态. 执行 ...
- STOMP协议详解
STOMP协议详解 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.STOMP协议介绍 STOMP即Simple (or Streaming) T ...
- @RequestMapping 和@ResponseBody 和 @RequestBody和@PathVariable 注解 注解用法
接下来讲解一下 @RequestMapping 和@ResponseBody 和 @RequestBody和@PathVariable 注解 注解用法 @RequestMapping 为url映射路 ...
- SQLAlcvchem
一.安装(稳定版的1.2.17) 二.一般使用(切记切记不要使用模块的名字作为项目名字,否则会出现玄学解决不了的问题------坑) #.导入SQLALchemy from sqlalchemy.ex ...
- JUnit@Before失效
在学习Shiro的过程中需要使用到JUnit@Before注解配合测试,但是无论如何,@Before下面的方法都不按照预期的执行,困扰良久,后来各种百度终于找到根源,今分享于诸公,望能解诸公之急: J ...
- Go开发[八]goroutine和channel
进程和线程 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位. 一个进程可以创 ...
- idea中@data不生效
idea中@data不生效,原因是idea中没有安装插件,记得重启
- 用例a失败,跳过测试用例b和c并标记失败xfail
前言 当用例a失败的时候,如果用例b和用例c都是依赖于第一个用例的结果,那可以直接跳过用例b和c的测试,直接给他标记失败xfail用到的场景,登录是第一个用例,登录之后的操作b是第二个用例,登录之后操 ...
- cmd 中文显示错误,解决办法
cmd窗口左上角控制按钮(就是图标)上单击-默认-选项-默认编码-936 追问 默认值是936的,但是属性里的当前代码页是437呀,怎么办 囧oz 追答 默认-选项-默认编码-936 不是属性,是 ...