【译】JavaScript如何工作的:一览引擎、运行时和调用栈

简介:

随着JavaScript(下文简称js)越来越流行,它在各个层面上都留下了身影:前端、后端、hybrid app、嵌入式设备等。

这篇文章是这个系列中第一个深入挖掘js是如何工作的:我们认为理解了js的底层建筑和运行方式可以使我们写出更好的代码和应用。

总览

应该很多人都听过V8引擎这个概念,也知道js是一个单线程的语言,还有它使用了回调队列。

这篇文章里我们会逐一解析每一个概念并解释js是怎么运行的。

如果你是js的初学者,那么这篇文章会让你了解为什么js比起其他语言会那么的“奇怪”。

如果你是js的高手,它会带给你一些关于你每天使用的js运行时是怎样工作的新颖知识。

JavaScript引擎

一个流行的js引擎是谷歌的V8引擎。它被使用在Chrome和Node.js中。这里简单地描述了他是什么样的:

1

引擎包含量两大部分:

  • 内存堆(Memory Heap)——内存分配的地方
  • 调用栈——这是你的代码执行时栈帧的位置

运行时

在浏览器中有很多被几乎每一位开发者使用的API(比如setTimeout)。这些API,却并不是引擎提供的。

所以,他们来自哪里?

事实上要复杂一点点。

1

除了引擎以外还有一些东西。我们把这些浏览器提供的东西叫做Web API,比如DOM,AJAX,setTimeout等。

图下方是大名鼎鼎的事件循环(event loop)回调队列( callback queue)

调用堆栈(Call Stack)

Js是一个单线程的语言。所以它也只有一个调用栈。这意味着它同时只能做一件事件。

调用栈是一个数据结构,基本上它记录了我们的程序运行到哪了。如果我们运行进一个函数,那么我们把它放在堆栈的顶部。如果我们从一个函数返回,那么我们弹出(pop off)堆栈顶部的函数。这是堆栈所做的工作。

我们来看一个例子:

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

当我们的引擎刚开始执行上述代码的时候,调用栈会是空。之后的步骤会如下图所示:

1

调用栈中的每一条都称作栈帧(Stack Frame)

这也解释了当发生异常的时候堆栈轨迹( stack traces)是怎么被建立起来的——其实就是异常发生时调用栈的状态。看下面的列子:

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

如果在Chrome中执行(假设运行的文件叫foo.js),会产生下面的堆栈轨迹:

"Blowing the stack"——这个异常发生在你达到了调用栈最大值的时候。这个很容易出现,特别是在你不小心错误地使用了递归的时候:

function foo() {
    foo();
}
foo();
复制代码

当引擎开始执行代码,我们会无止尽地执行这个函数。所以这个函数被不断地堆在调用栈上面,就像这样:

1

这时候浏览器会爆出:

1

代码运行在单线程的环境是一个很轻松的事,你不必担心一些多线程带来的复杂场景——比如,死锁。

但是单线程也有一些限制。js只有一个调用栈,如何其中一些东西运行很慢怎么办?

并发 & 时间循环

当您在调用栈中行调用需要花费大量时间才能的函数时,会发生什么情况?比如你想在浏览器中进行图像处理。

你可能会问——这为什么会有问题?问题在于调用栈中有函数在执行,浏览器不能做其他的事情。这意味着浏览器不能渲染,不能跑其他代码。这会成为流畅UI界面的阻碍。

而且,一旦你的浏览器要处理太多的任务了,它会失去响应。一些浏览器会采取行动,询问你是否终止这个网页。

1

所以我们不卡死浏览器且拥有流畅UI的情况下执行大量代码呢?解决方案是异步调用

这会在本系列的下一篇文章中提到:“Inside the V8 engine + 5 tips on how to write optimized code”。(译注:后续翻译尽请关注)


作者:Skandar-Ln
链接:https://juejin.im/post/5b346d416fb9a00e6a621cc4
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章
|
5月前
|
JavaScript 前端开发 Serverless
函数计算只支持Node.js,我用C++写的程序怎么运行?
函数计算只支持Node.js,我用C++写的程序怎么运行?
93 1
|
3月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
81 0
|
4月前
|
JavaScript 前端开发 API
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(下)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
37 0
|
1天前
|
JavaScript 前端开发 NoSQL
【MongoDB 专栏】MongoDB 的 JavaScript 引擎与脚本执行
【5月更文挑战第11天】MongoDB 的 JavaScript 引擎允许在服务器端直接执行脚本,提升效率并实现定制化操作。脚本环境提供独立但与数据库关联的运行空间,引擎负责脚本的解析、编译和执行。执行过程包括脚本提交、解析、编译和执行四个步骤。掌握脚本逻辑设计和 JavaScript 语言特性对于高效利用这一功能至关重要。例如,通过脚本可以计算商品总销售额,增强数据库操作的灵活性。
【MongoDB 专栏】MongoDB 的 JavaScript 引擎与脚本执行
|
1天前
|
移动开发 资源调度 前端开发
nbcio-vue下载安装后运行报错,diagram-js没有安装
nbcio-vue下载安装后运行报错,diagram-js没有安装
|
24天前
|
JavaScript 前端开发 开发者
在JavaScript中,可以利用以下几种输出语句来查看运行结果
【4月更文挑战第18天】在JavaScript中,可以利用以下几种输出语句来查看运行结果
24 1
|
25天前
|
JavaScript 前端开发
用js使鼠标放轮播图上使其停止,移开鼠标轮播图继续运行
用js使鼠标放轮播图上使其停止,移开鼠标轮播图继续运行
9 0
|
2月前
|
JavaScript 前端开发 Serverless
函数计算新功能— 支持 Node.js 18 、Node.js 20 运行时
从2024年2月起,函数计算正式发布 Node.js 18 运行时和 Nodejs.20 运行时,函数计算2.0和函数计算3.0都支持新的运行时,目前新运行时处在公测状态,欢迎大家来体验。
481 0
|
2月前
|
JavaScript 前端开发 开发者
如果你想在钉钉环境中运行JavaScript脚本
【2月更文挑战第17天】如果你想在钉钉环境中运行JavaScript脚本
38 6
|
3月前
|
JavaScript 前端开发 算法
【Node.js 版本过高】运行前端时,遇到错误 `Error: error:0308010C:digital envelope routines::unsupported`
【Node.js 版本过高】运行前端时,遇到错误 `Error: error:0308010C:digital envelope routines::unsupported`
84 0