javasctipt 工作原理之调用栈

译者注

翻译一个对新手比较友好的 JavaScript 工作原理解析系列文章

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

正文从这里开始

随着 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 都是使用这个引擎,这里是一个简单的他看起来是什么的图

图片描述

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

  • memory Heap: 这是内存分配的位置
  • call Stack: 这是你的代码执行时,堆栈帧(starck frame)的位置

运行时

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

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

其实这有点复杂.

图片描述

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

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

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

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

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

让我们来看一个例子:

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 以结束这个函数的执行.

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

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

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

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

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

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

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

图片描述

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

图片描述

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

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

并发和事件循环(even loop)

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

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

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

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

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

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

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

原文第二篇我会尽快翻译,尽量不拖太久.

写作新手,还望大家多多关注,多多点赞.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值