乐趣区

关于翻译:javascript是如何工作的引擎运行时和调用栈的概述

随着 JavaScript 的越来越风行,促使团队在多个栈上都须要它反对 – 前端、后端、混合应用程序、嵌入式设施等等。

这篇文章是这个系列的第一篇,目标是深入研究 JavaScript 以及它真正是如何工作的:咱们认为理解 JavaScript 的构建块,并且晓得它是如何一起运行的,那么你将会写出更好的代码和应用程序。咱们也将分享一些咱们在应用构建 SessionStatck 时候的一些教训规定,一个轻量的应用程序,为了放弃竞争力,必须是强壮和高性能的。

正如GitHut statsGitHut – Programming Languages and GitHub 统计数据展现,JavaScript 是 GitHub 上 Repositories 最沉闷和 push 最多的语言。在其余的类别中,它也没有落后。

获取最新的 GitHub language stats)

如果我的项目越来越多的依赖 JavaScript,这意味着开发者为了构建一个令人惊叹的软件,必须利用语言提供的所有,并且对于生态系统外部有着深刻的了解。

事实证明,很多开发者每天都在应用 JavaScript,然而并不知道它们外部产生了什么。

概述

简直每个人都曾经据说过 V8 引擎的概念,并且很多人晓得 JavaScript 是单线程的或者它是应用回调队列的。

在这篇文章中,咱们将会具体讲述所有的概念,并且解释 JavaScript 是如何真正运行的。在晓得这些字节之后,你将会适当的利用提供的 APIS 写出更好的,非阻塞的应用程序。

如果你是 JavaScript 老手,这篇文章会帮忙你了解为什么 JavaScript 和其余语言比拟起来如此“怪异”。

如果你是一个有教训的 JavaScript 开发者,心愿它能够让你对每天都在应用的 JavaScript 运行时是如何真正关注的有一些新的了解。

JavaScript 引擎

最风行的 JavaScript 引擎的例子是谷歌的 V8 引擎。V8 被用于 Chrome 和 Node.js 外部。上面是一个简略的视图示例:

引擎次要由两个局部组成:

  • 内存堆 — 这是内存调配的中央
  • 调用栈 — 这是代码执行的栈

运行时

有很多浏览器的 APIS 被 JavaScript 开发者应用过(例如:setTimeout)。然而这些 APIS,并不是引擎提供的。

那么,他们从哪里来?

事实证明这真的有一些简单。

因而,咱们有引擎,但实际上有更多。咱们有浏览器提供的 Web APIs,例如:DOM,AJAX,setTimeout 等。

接下来,咱们有十分风行的 event loopcallback 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,并且浏览器有响应的状况下执行大量代码?解决方案就是 异步回调

这个将会在“浏览器是如何工作的”第二局部“V8 引擎和 5 个如何优化代码的 tips”中具体介绍。

与此同时,如果你在你的应用程序中有很难重现或者很难了解的问题的时候,看下 SessionStack。SessionStack 记录你的 web 应用程序的所有货色:所有的 DOM 变动,用户交互,JavaScript 异样,栈追踪,失败的网络申请和调试信息。

应用 SessionStack,你能够重当初你的 web 利用中的所有问题就像视频一样,并且能够看到你的用户交互信息。

这里有一个收费的打算,不须要信用卡。当初开始就开始吧。

退出移动版