JavaScript执行模型

引言

JavaScript是一个单线程(Single-threaded)异步(Asynchronous)非阻塞(Non-blocking)并发(Concurrent)语言,这些语言效果通过一个调用栈(Call Stack)、一个事件循环(Event Loop)、一个回调队列(Callback Queue)有些时候也叫任务队列(Task Queue)与跟运行环境相关的API组成。

概念

调用栈 Call Stack

调用栈是一个LIFO后进先出数据结构的函数运行栈,它内部的数据结构为函数帧。当在JavaScript中调用一个函数时,它将被压入栈中,当这个函数内部还有另一个函数被调用时,另一个函数将会被压入栈顶,直到其内部没有更多调用,栈顶函数将会被以单线程方式执行并出栈,直到最后一个函数帧出栈。JavaScript语言特性中的单线程就是指的调用栈的单线程运行。

function multiply(a, b) {
return a * b;
} function square(n) {
return multiply(n, n)
} function printSquare(n) {
console.log(square(n));
} printSquare(4);

首先调用栈压入main(),扫描到printSquare()函数调用调用栈压入printSquare(4)printSquare函数内部调用square(n)该函数被压入栈,同理multiply(n, n)函数也被压入栈且没有更多调用,JavaScript引擎开始执行栈顶函数multiply(n, n)返回结果并出栈,以此类推直到main()函数出栈。

调用栈有一个意外情况,当函数递归调用其自身时调用栈将溢出,执行环境将报错。

function foo() {
foo();
}
foo();

任务队列 Task Queue

任务队列是WebAPI的一部分,也就是说它本身并不是ECMAScript标准的一部分,而是运行环境自行实现的。任务队列是所有回调函数排队执行的FIFO先进先出队列,它的单位是任务(Task),每个任务都关联着一个用于处理这个任务的回调函数。在事件循环(Event Loop)中会将任务队列内的函数压入调用栈执行并出队列,直至为空。

任务队列在浏览器的实现中被分为了宏任务队列(macrotask queue)和微任务队列(microtask queue),它们分别个自承载宏任务(macrotask)和微任务(microtask)的排队,其中宏任务队列与宏任务又被默认为常规的任务队列与任务。

当调用栈内所有调用都完成执行后,事件轮询会在每次处理宏任务队列的一个宏任务后处理微任务队列的全部微任务,也就是微任务基本会在宏任务处理之前被处理。微任务处理中间不会被UI或网络事件处理被执行,微任务执行是连续的。

会被添加到宏任务的方法的回调有:

  • script:script标签中的代码解析运行
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering:UI渲染,每16.6ms放到队列上一次,60fps,如果调用栈被占用则会被阻塞

会被添加到微任务的Web API方法有:

  • process.nextTick:Node提供的
  • Promise
  • Object.observe
  • MutationObserver

微任务只会从我们编写的代码中产生,宏任务既可能从我们编写的代码中产生也可能从浏览器本身事件、渲染、IO产生。

事件循环 Event Loop

事件循环是JavaScript的事件处理机制,它会一直轮询消息队列,当满足调用栈为空且消息队列不为空时,它将把消息队列队头的消息压入执行栈。这样的机制保证了函数不会被中断,不会有线程切换带来的数据不一致等情况

事件循环在调用栈为空时轮询,顺序为

  1. 找到任务队列(宏任务队列)的最早被添加的任务并将其添加到调用栈执行
  2. 执行所有微任务队列内的任务
    • 当微任务队列不为空时找到微任务队列最早被添加的任务并将其添加到调用栈执行
  3. 渲染所有变化
  4. 如果宏任务队列为空等待宏任务出现
  5. 返回步骤1

JavaScript运行时 Runtime

浏览器的JavaScript代码执行也就是调用栈与堆(用于储存变量对象等)由JavaScript引擎提供,用的比较多的是谷歌的V8引擎,Chrome、Edge浏览器、Nodejs均使用该引擎。

事件循环Event Loop、任务队列Task Queue(回调队列Callback Queue)、WebAPI或Node API由运行环境提供。

JavaScript执行模型笔记的更多相关文章

  1. JavaScript对象模型-执行模型

    数据类型基本数据类型基本数据类型是JS语言最底层的实现.简单数值类型: 有Undefined, Null, Boolean, Number和String.注意,描述中的英文单词在这里仅指数据类型的名称 ...

  2. [Clr via C#读书笔记]Cp1CLR执行模型

    Cp1CLR执行模型 本章的概念点 CLR=Common Language Runtime 内存管理,程序集加载,安全性,异常处理和线程同步.CLR是基础,支持着面向它的各种语言.各种语言会被对应的编 ...

  3. 转:JS高级学习笔记(8)- JavaScript执行上下文和执行栈

    必看参考: 请移步:博客园 JavaScript的执行上下文 深入理解JavaScript执行上下文和执行栈 JavaScript 深入之执行上下文 写在开头 入坑前端已经 13 个月了,不能再称自己 ...

  4. JavaScript 执行环境(执行上下文) 变量对象 作用域链 上下文 块级作用域 私有变量和特权方法

    总结自<高程三>第四章  理解Javascript_12_执行模型浅析   JS的执行环境与作用域  javascript高级程序第三版学习笔记[执行环境.作用域] 在javascript ...

  5. 【MarkMark学习笔记学习笔记】javascript/js 学习笔记

    1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...

  6. javascript正则表达式 - 学习笔记

    JavaScript 正则表达式 学习笔记 标签(空格分隔): 基础 JavaScript 正则表达式是用于匹配字符串中字符组合的模式.在javascript中,正则表达式也是对象.这些模式被用于Re ...

  7. JavaScript闭包模型

      JavaScript闭包模型 -----  [原创翻译]2016-09-01  09:32:22 < 一>  闭包并不神秘 本文利用JavaScript代码来阐述闭包,目的是为了使普通 ...

  8. Javascript事件模型系列(四)我所理解的javascript自定义事件

    被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...

  9. JavaScript语言精粹笔记

    JavaScript语言精粹笔记 掌握语言的每个特性可以让你出风头,但是并不推荐,因为一部分的特性带来的麻烦可能远超本身的价值.正如书中所言,坏的材料并不能雕刻出好的作品,要成为一名更好的程序员,要取 ...

  10. javascript高级编程笔记01(基本概念)

    1.在html中使用JavaScript 1.  <script> 元素 <script>定义了下列6个属性: async:可选,异步下载外部脚本文件. charset:可选, ...

随机推荐

  1. 动态尺寸模型优化实践之Shape Constraint IR Part II

    简介: 在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考.本次分享的是我们最近开展的有关shape constraint IR的工作,Part II 中我们将 ...

  2. WPF 将控件放入到 UserControl 里获取 HwndSource 为空的情况

    本文记录将 WPF 控件放入到 UserControl 里,如果此 UserControl 没有被设置 Visibility 为可见过,那么放在此 UserControl 内的控件将获取不到 Hwnd ...

  3. .NET开源、功能强大、跨平台的图表库 - LiveCharts2

    前言 今天大姚给大家分享一个.NET开源(MIT License).功能强大.简单.灵活.跨平台的图表.地图和仪表库:LiveCharts2.   项目介绍 LiveCharts2是一个.NET开源. ...

  4. oracle RDBMS Kernel Executable 占用内存过高

    oracle RDBMS Kernel Executable 占用内存过高 参考:https://www.cnblogs.com/markkang/archive/2019/11/25/1192540 ...

  5. easyExcel多行表头设定不同样式和特定单元格设定样式的实现

    前言 有个需求,需要设置Excel导出的样式,样式如下图所示,有三个表头行,第一个表头行需要加粗和灰色背景,另外两个表头行使用另外的样式,并且当测试结果单元格出现x或者未通过的时候,设置其为红色字体. ...

  6. Docker手工部署GO环境

    参考: (最新2020)Golang 使用Dockerfile 打包部署到 docker https://blog.csdn.net/weixin_44042863/article/details/1 ...

  7. 鸿蒙HarmonyOS实战-ArkUI事件(手势方法)

    一.手势方法 应用程序的手势操作是指在移动设备上使用手指或手势进行与应用程序交互的方式.手势操作可以包括点击.滑动.双击.捏合等动作,用于实现不同的功能和操作. HarmonyOS中常见的手势操作及其 ...

  8. Python——基本输入和输出

    Python提供了基本的输入和输出功能,这些功能通常是通过内置的input()函数(用于输入)和print()函数(用于输出)来实现的.以下是这两个函数的详细描述和示例: 1. print() 函数( ...

  9. Threading Programming Guide:One

    苹果支持的产生线程的方式 Operation Object 使用OperationQueue,具体可以参考:Concurrency Programming Guide GCD 使用诸如dispatch ...

  10. vue中v-for说明

    v-if vs v-show区别v-if:每次显示与否,都会执行销毁和重建,渲染开销较大v-show:始终会被渲染并保留在DOM中.只是简单地切换display属性.频繁切换的时候用v-if,较少切换 ...