详解JavaScript执行模型
作者:CamWang 发布时间:2024-07-26 01:05:12
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方法有:
会被添加到微任务的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由运行环境提供。
来源:https://www.cnblogs.com/camwang/p/13975164.html


猜你喜欢
- 对于Vue.js来说,如果你想要快速开始,那么只需要在你的html中引入一个<script>标签,加上CDN的地址即可。但是,这
- 1.设置phpMyAdmin Language:Chinese simplified (zh-utf-8)MySQL 字符集:UTF-8 U
- 本文实例讲述了Python实现网络端口转发和重定向的方法。分享给大家供大家参考,具体如下:【任务】需要将某个网络端口转发到另一个主机(for
- 前言众所周知,appsetting.json 配置文件是.Net 的重大革新之心,抛开了以前繁杂的xml文件,使用了更简洁易懂的json方式
- 因为最近在做文本检测相关,想试着用用百度的paddle框架。1、安装Anaconda3官网下载安装包直接运行安装,然后新建python3.7
- 引言本身打算先写完sync包的, 但前几天在复习以前笔记的时候突然发现与字符串相关的寥寥无几. 同时作为一个Java选手, 很轻易的想到了几
- 下载和安装安装 WTForms 最简单的方式是使用 easy_install 和 pip:easy_install WTForms# orp
- 1. 加载数据集这次我们搭建一个小小的多层线性网络对糖尿病的病例进行分类首先先导入需要的库文件先来看看我们的数据集观察可以发现,前八列是我们
- 一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配
- 本文实例讲述了MySQL数据库入门之多实例配置方法。分享给大家供大家参考,具体如下:前面介绍了相关的基础命令操作:MySQL数据库基础篇之入
- 开门见山,直接使用 skimage 库为图像添加高斯噪声是很简单的:import skimageorigin = skimage.io.im
- table通过使用下面语句创建:create table userinfo(name text, email text)更快地插入数据在此用
- 读写中文需要读取utf-8编码的中文文件,先利用sublime text软件将它改成无DOM的编码,然后用以下代码:with codecs.
- JavaScript Length 字符长度函数,在很多时间我们会用length函数了,因为你得前台判断一个用户输入
- 池化层定义在tensorflow/python/layers/pooling.py.有最大值池化和均值池化。1、tf.layers.max_
- 本文实例讲述了Python实现Windows上气泡提醒效果的方法。分享给大家供大家参考。具体实现方法如下:# -*- encoding: g
- 本文实例讲述了Python实现采用进度条实时显示处理进度的方法。分享给大家供大家参考,具体如下:前言在大多数时候,我们的程序会一直进行循环处
- 设计首页的第一步是设计版面布局。就象传统的报刊杂志编辑一样,我们将网页看作一张报纸,一本杂志来进行排版布局。虽然 * 页技术的发展使得我们开
- 原贴:http://www.blueidea.com/bbs/NewsDetail.asp?id=216190首先说明一下,这里只是部分整理
- TEMPLATESDjango 1.8的新特性一个列表,包含所有在Django中使用的模板引擎的设置。列表中的每一项都是一个字典,包含某个引