简评:JavaScript 是越来越受欢迎了,很多团队都在采用这些语言工作。前端、后端、嵌入式设备等等,都可以看见它的身影。虽然我们知其然,但又知其所以然吗?

大家应该都知道 JavaScript 是单线程的,以及听过 V8 引擎的概念。
这篇文章将会介绍这些概念,并解释 JavaScript 是如何运行的。通过了解这些细节,开发者能更好地编写代码,正确利用其提供的 API。

JavaScript 引擎

比较流行的一个 JavaScript 引擎示例就是 Google 的 V8 引擎。下图是 V8 引擎在 Chrome 和 Node.js 中使用的一个简化视图:

引擎主要由两个组件组成:

  • 内存堆(Memory Heap ):这是内存分配的地方
  • 调用堆栈(Call Stack):这是程序运行时函数的调用过程

运行

在浏览器中,例如「setTimeout」这样的 API 已经有很多开发者在用了,然后引擎并没有提供这些 API,所以它们从哪里来的呢?
实际情况是这样的:

所以,除了引擎之外,还有浏览器提供的 Web API(像 DOM、AJAX、setTimeout 等等)。另外,还有事件循环(event loop)和回调队列(callback queue)。

调用堆栈(Call Stack)

JavaScript 是单线程语言,这意味着它只有一个单一的调用堆栈。因此,它每次只能做一件事。

调用堆栈是一个数据结构,按调用顺序保存所有在运行期被调用的方法。既然是个栈,那么它就满足先入后出的特性。

我们来看一个例子:

1
2
3
4
5
6
7
8
function (x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);

当引擎开始执行这段代码时,调用堆栈将为空。然后,就会有以下步骤:

调用堆栈中的每个条目称为堆栈帧(Stack Frame)。当异常发生时,它基本上是调用堆栈的状态。再看看下面这段代码:

1
2
3
4
5
6
7
8
大专栏  JavaScript是如何工作的(一)ne">9
10
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();

如果这是在 Chrome 中执行(假设此代码位于一个名为 foo.js 的文件中),则会产生这种情况:

当你达到最大调用堆栈时,会容易发生这种情况,特别是在没有测试代码时随意使用递归。
看看这个示例代码:

1
2
3
4
function foo() {
foo();
}
foo();

代码执行时,首先调用函数「foo」。然而,这是递归函数,调用自身的同时又没有设置终止条件,所以每一次执行,相同的函数都会被添加进堆栈中,看起来就是这样:

某些时候,调用堆栈中的函数调用次数超过了调用堆栈的实际大小,那么浏览器就会抛出一个错误,看起来像这样:

单线程上编写代码相对多线程来说会简单得多,你不必考虑死锁这样的复杂场景。但单线程也有许多限制,由于 JavaScript 有调用堆栈,当执行代码需要耗费大量时间时是怎样的呢?

并发和事件循环

当你在调用堆栈中进行函数调用,有时候需要大量时间才能进行处理。例如在浏览器中使用JavaScript 进行一些复杂的图像转换。在这个过程中又发生了什么?
这个问题的产生是因为,虽然调用堆栈具有执行的功能,但浏览器本身是无法渲染也不能运行其他任何代码,它被卡住了。当你想执行一套流畅的 UI 时,就会产生这样的问题。大多数浏览器通过抛出异常处理错误,询问用户是否要终止网页:

这个用户体验很糟糕。那么如何解决呢?答案是异步回调(asynchronous callbacks)。这是后话,下次再讲。

翻译和参考 https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf

JavaScript是如何工作的(一)的更多相关文章

  1. this在JavaScript中的工作范围

    this在JavaScript中的工作范围 在一个函数中,this的行为,取决于JavaScript函数的调用方式和定义方式,而不仅仅是看它如何被定义的. var fullname = 'Fu';va ...

  2. JavaScript 是如何工作的:JavaScript 的共享传递和按值传递

    摘要: 原始数据类型和引用数据类型的副本作为参数传递给函数. 原文:JavaScript 是如何工作的:JavaScript 的共享传递和按值传递 作者:前端小智 Fundebug经授权转载,版权归原 ...

  3. JavaScript 是如何工作的:JavaScript 的内存模型

    摘要: 从内存角度理解 let 和 const 的意义. 原文:JavaScript 是如何工作的:JavaScript 的内存模型 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这 ...

  4. JavaScript是如何工作的:引擎,运行时和调用堆栈的概述!

    摘要: 理解JS执行原理. 原文:JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 本文是旨在深入研究JavaScrip ...

  5. JavaScript是如何工作的:编写自己的Web开发框架 + React及其虚拟DOM原理

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 19 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  6. JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  7. JavaScript是如何工作的:深入类和继承内部原理 + Babel和TypeScript 之间转换

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 15 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  8. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  9. JavaScript是如何工作的:使用MutationObserver跟踪DOM的变化

    摘要: 掌握MutationObserver. 这是专门探索 JavaScript 及其所构建的组件的系列文章的第10篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工 ...

  10. JavaScript是如何工作的: Web推送通知的机制

    摘要: 如何在Web端推送消息? 这是专门探索 JavaScript 及其所构建的组件的系列文章的第9篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript是如何工作的:引擎,运行时 ...

随机推荐

  1. Django_JavaScript

    JavaScript是什么 JavaScript是一种运行在客户端(浏览器)的编程语言,用来给网页添加动态功能. JavaScript的作用 最初目的 为了处理表单的验证操作 现在广泛的应用场景 网页 ...

  2. 机器学习总结(参考源码ml.hpp)

    依据机器学习算法如何学习数据可分为3类: 有监督学习:从有标签的数据学习,得到模型参数,对测试数据正确分类: 无监督学习:没有标签,计算机自己寻找输入数据可能的模型: 强化学习(reinforceme ...

  3. java.lang.SecurityException: java.lang.IllegalStateException: java.io.FileNotFoundException:XXXXXX(系统找不到指定文件)

    项目启动成功过,但访问页面抛出异常. 在Maven项目启动的时候,tomcat缓存机制没有吧maven jar除外的jar执行到项目里面,所有不要慌,项目重新启动就OK了, 如果这样还是不行的话就找到 ...

  4. 600E - Lomsat gelral(找子树多颜色问题)(入门)

    题:https://codeforces.com/problemset/problem/600/E 题意:一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和 ...

  5. tomcat更新class不生效

    替换线上lib里的class不生效,需要想想是不是前人为了图方便在classes里面扔了一份老版本class

  6. Linux centos 下安装nginx

                     一.安装编译工具及库文件      yum -y install make zlib zlib-devel gcc-c++ libtool openssl opens ...

  7. FastJson禁用循环引用检测

    我们先来看一个例子: package com.elong.bms; import java.io.OutputStream; import java.util.HashMap; import java ...

  8. jmeter 配置csv 登陆网站 报错

    0 环境 系统环境:win7 1 正文 1 问题 创建csv 格式为utf-8后 jmeter csv配置好后 post请求登陆报错 2 解决 查看了一下报告 post请求里用户名乱码了 仔细一看网站 ...

  9. tap点击一次,内部程序执行两次,多次

    调试过程发现,使用 $(document).on('tap', '.children2', function () { //内部程序 }) 点击children2的时候,程序在里面执行了两次.百度得到 ...

  10. day43-线程概念

    #1.进程:程序不能单独运行,要将程序加载到内存当中,系统为它分配资源才能运行,而这种执行的程序就是进程. #程序和进程的区别在于:程序是指令的集合,它是进程运行的静态描述文本:进程是程序的一次执行活 ...