javasctipt 工作原理之调用栈

# 译者注

medium 是一个国外高质量论坛,里面的文章主打高质量,涉及的领域广泛,笔者于翻墙后不久,在学习react的时候,有一些动画问题百度不出来,然后去了google,最后搜到一篇,真正解决了我的问题的文章,经过一翻查阅,发现能在这个网站发布文章的人,都是有实力的人,而且文章都是原创,由于需要翻墙,而且是全英,小弟就在此为国内新手,且英文能力欠缺的开发者提供一丁点的帮助.(本人英文能力也是水得一匹,没把握的点我会以自己的理解翻译并且把原文或者解释写在圆括号里)

注意: 以下全部是概念,经验丰富的老鸟可以离场啦

------------------------

正文从这里开始

随着 javascript 的流行,团队们正在利用javascript来支持多个级别的技术栈,包括前端,后端,混合开发,嵌入式设备,以及更多

这篇文章旨在成为`深入挖掘JavaScript和实际上他是怎么工作的`系列文章中的第一篇:我们通过知道javascript的模块(Building blocks)和他们如何组合在一起工作来写更好的代码和应用.我们还会分享一些我们构建sessionStarck(这是一款主打反馈功能的产品)时的经验法则,一款轻量级的javascript应用为了保持竞争力,必须时要健壮和高性能.

据githut stats(这是一个统计网站,根据gihub的数据来进行语言统计)的数据来看 , JavaScript 是github 上 活跃库最多的,和提交数最多的语言,这让他不会落后于其他类别.

如果项目变得如此依赖于JavaScript,这就意味着,为了开发惊艳的软件(可以理解为程序),开发者不得不利用这个语言和生态系统(JavaScript生态)提供的一切,对内部的更深入和更深入的了解.

事实证明,有很大一部分的开发者每天都在使用javascript,但是却不知道javascript 在底层干了啥(原文很长,其实就是这个意思,英文还真的是...)

## 上面在扯(外国人也挺喜欢扯的),现在应该开始了(原文这个标题叫Overview)

基本上每个人都知道 v8 引擎这个概念了,大多数人知道javascript 是一个单线程语言 或者是那个使用回调队列的语言.

这篇文章,我们将跑通哪些概念的细节和说明javascript是如何运行的,通过知道这些细节,你能够正确的使用提供的api书写更好的,非阻塞的应用.

如果你是一个javascript新手,这篇文章能让你知道为什么javascript对比与其他语言,为什么如此神奇.

如果你是一个有经验的javascript开发者,我也希望如此,这会给你一些关于javascript运行时是怎么工作的闪亮的灵感(或者说新的见解).

## javascript引擎(尼玛现在才开始)

google v8 引擎是一个了流行的例子,nodejs 和 chrome 都是使用这个引擎,这里是一个简单的他看起来是什么的图


javasctipt 工作原理之调用栈_第1张图片

这个引擎看起来像是两个组件.

* memory Heap: 这是内存分配的位置

* call Stack: 这是你的代码执行时,堆栈帧(starck frame)的位置

## 运行时

在浏览器中有一些api已经被几乎所有的javascript开发者使用了,例如 setTimeout 这些api,然而,他们不是又引擎提供的.

那么,他们从哪里来的呢?

其实这有点复杂.(下面怕是要听不懂了)


javasctipt 工作原理之调用栈_第2张图片

看,我们有引擎,但是其实我们还有很多东西.我们有那些浏览器提供的web apis,例如 DOM, AJAX, setTimeout等等.

而且,我们还有流行的事件循环(even loop)和回调队列(callback queue)

## 调用栈(回调队列跟调用栈其实意思差不多,不过栈跟队列是两种不同的数据结构)

javascript是一个单线程的编程语言(repeat又repeat,都说几次了),这意味着他有一个调用栈,因此,他一次只能做一件事情.

调用栈是一个记录了我们在程序中的位置的数据结构,如果我们跳进一个function,我们把这个函数放进栈的顶部(栈是一种先进后出的数据结构),如果我们从function中return出来,我们就从栈的顶部跳了出来,这就是栈能做的事情.

让我们来看一个例子:

```js

function multiply(x, y) {

    return x * y;

}

function printSquare(x) {

    var s = multiply(x, x);

    console.log(s);

}

printSquare(5);

```

当引擎执行这段代码的时候,调用栈(call stack)是空的,当进入printSquare的时候,栈上添加了一个函数,在printSquare中我们又进入了multiply中,此时栈的顶部又添加了一个函数,当我们从multiply中return的时候,栈就把顶部的函数弹出,此时我们就回到了printSquare里,然后执行完printSquare后引擎自动return undefined 以结束这个函数的执行.

栈的每一次变化就想下面这样:


javasctipt 工作原理之调用栈_第3张图片

栈中的每一个条目(entry)叫坐堆栈帧(stack frames)上面有提到

这就是一个异常抛出时,栈追踪是如何被构造的(how stack traces are being constructed)---这取决于异常发生的时候,回调栈的状态.(突然跑异常去了,其实是想说明,异常就是通过调用栈实现的)

```js

function foo() {

    throw new Error('SessionStack will help you resolve crashes :)');

}

function bar() {

    foo();

}

function start() {

    bar();

}

start();

```

如果这段代码在chrome执行,会产生下边的栈追踪(其实就是一个错误)

"栈坏了"(blowing the stack) --- 这发生在当你把栈放满了的时候(下面还说了一大推,还贴了代码,其实就是死递归)

当引擎执行死递归的时候,会不停的调用同一个方法.看起来像下面这样.


javasctipt 工作原理之调用栈_第4张图片

然而,函数在调用栈上调用的数量超过了调用栈的实际大小,浏览器决定要采取行动了,所以他抛出了一个错误,看起来是这样的


在单线程上运行代码可以很容易,因为你不用去处理多线程中的复杂场景,例如,死锁.

但是,运行在单线程上也有他的限制,由于javascript只有一个调用栈,若是程序执行得很慢怎么办?

## 并发和事件循环(even loop)

当你有函数调用在调用栈(call stack)里为了一个任务花费了大额的时间会发生什么?例如,想象一下,你要在浏览器了做一个复杂的图片转性(transfromation).

你可能会问--为什么这是一个问题?问题是调用栈有函数在运行,浏览器就不能做其他的事情,这就造成了阻塞,这意味这浏览器不能渲染,它不能运行任何的其他代码,它卡住了,如果你想你的app 的ui界面流畅,那么这就是一个问题.

然而,这不是唯一的问题,一旦你的浏览器在调用栈开始了很多的任务,这可能会在很长的一段时间内失去响应.而很多的浏览器会抛出一个错误,然后问你是否要关闭网页.

现在,这不是一个最好的用户体验,对吧?

那么,我们要如何处理这种需要很长时间执行的代码呢?嗯~,解决办法就是异步回调

这会再第二篇文章中详细说明.

下面开始买他们产品的广告了,就不翻译了.

原文第二篇我有尽快找时间翻译,尽量不让读者等太久.

写作新手,还望大家多多关注,多多点赞.让我小小的开心一下呗.

原文

你可能感兴趣的:(javasctipt 工作原理之调用栈)