JS学习篇(七)—— 执行机制

V8是如何执行一段代码的

全局过程:如下图在这里插入图片描述
第一步:生成抽象语法树(AST)和执行上下文
将源代码转化为抽象语法树,并生成执行上下文,这里主要说一下什么是抽象语法树,简称AST

为什么要转化为AST:高级语言是开发者可以理解的语言,但是让编译器或者解释器来理解就很困难,对于他们来说,能理解的就是AST,所以无论你使用的是解释型语言还是编译型语言,在编译的过程中,他们都会生成一个AST

如下面的代码:

1 var myName = " 极客时间 "
2 function foo(){
3 	return 23;
4 } 
5 myName = "geektime"
6 foo()

经过处理之后生成的AST结构如下图:在这里插入图片描述
生成了AST抽象语法树之后,编译器或者解释器后续的工作都要依赖于AST,而不是源代码

AST的作用:是一种非常重要的数据结构,有着广泛的应用。
1:其中最常见的就是babel,babel是一个被广泛使用的代码转换器,可以将ES6代码转化为ES5代码,通过这样的方式可以解决有的浏览器无法ES6的语法的问题,而babel的转换原理就是先将ES6源码转化为AST,然后在将ES6语法的AST转化为ES5语法的AST,最后再利用ES5的AST生成JavaScript源代码
2:eslint也使用AST,eslint是一个用来检查JavaScript编写规范的插件,其检测流程也需要将源代码转化为AST,然后再利用AST来检查代码的规范化问题

介绍完AST的作用,具体来看看AST到底是如何生成的

AST的生成过程
1:词法分析,又称分词(tokenize),就是将一行行的源码拆解成为一个个token(指语法上不可能在分的,最小的单个字符或字符串)
2:语法分析,又称解析(parse),作用是将上一步生成的token数据,根据语法规则转为AST,如果源码符合语法规则,则这一步就会顺利完成,但是如果源码存在语法错误,这一步就会终止,并且抛出一个语法错误

第二步:生成字节码

什么是字节码?
字节码就是介于AST和机器码之间的一种代码,但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码之后才可以执行
为什么要使用字节码?
之前没有字节码的时候,是直接将AST转换为机器码,在最初的时候,执行机器码效率很高,这种方式在发布一段时间内运行效果非常的好,但是随着Chrome在手机上的广泛普及,内存占用问题也暴露出来,因为V8需要消耗大量的内存来存放转换后的机器码,为了解决内存占用问题,引入字节码
在这里插入图片描述

第三步:执行代码
生成字节码之后,然后解析器对字节码进行解析

通常,如果有一段第一次执行的字节码,解析器会逐条解释执行,在执行字节码的过程中,如果发现有热点代码(一段代码被重复执行多次,称为热点代码),那么后台的编译器就会把这段热点代码的字节码编译为高效的机器码,当再次执行这段被优化的代码的时候,只需要执行编译后的机器码就行

字节码配合解释器和编译器是的这种技术,我们称为即时编译(JIT)

事件循环EventLoop

宏任务
在JS中,大部分的任务都是在主线程中执行的,常见的任务有:
1:渲染事件(解析DOM,计算布局,绘制)
2:用户交互事件(如鼠标点击,滚动页面,放大缩小等)
3:JS脚本执行事件
4:网络请求,文件读写完成事件

为了协调这些任务有条不紊的在主线程上执行,页面进程引入了消息队列和事件循环机制,渲染进程内部会维护多个消息队列,比如延迟执行队列(专门处理类似于setTimeout/setInterval这样的定时器回调任务)和普通的消息队列,然后主线程采用一个for循环,不断的从这些任务队列中取出任务并执行任务,我们把这些消息队列中的任务称为宏任务,所以setTimeout和setInterval是宏任务

微任务

引入微任务是为了解决异步回调的问题,常见的微任务有:MutationObserverPromise.then(或.reject) 以及以 Promise 为基础开发的其他技术(比如fetch API), 还包括 V8 的垃圾回收过程

在每一个宏任务中定义一个微任务队列,当这个宏任务完成的时候,就回去检查微任务队列,如果为空则直接执行下一个宏任务,如果不为空,则依次执行微任务,执行完成采取执行下一个宏任务

EventLoop

console.log('start');
setTimeout(() => {
  console.log('timeout');
});
Promise.resolve().then(() => {
  console.log('resolve');
});
console.log('end');

执行过程:
1:刚开始整个脚本作为一个宏任务来执行,对于同步代码直接压入栈中执行,所以先打印start和end
2:setTimeout作为一个宏任务加入宏任务队列
3:promise.then作为一个微任务放入微任务队列
4:当本次宏任务执行完之后,会去检查微任务队列,发现有要执行的promise.then然后执行
5:执行完成之后进入到下一个宏任务setTimeout,继续执行

所以整个事件循环的过程为:

1:脚本作为第一个宏任务执行
2:执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列,
3:当前宏任务执行完成之后出队,然后去检查微任务队列,如果有的话就依次执行,知道微任务队列为空
4:执行浏览器UI线程的渲染工作
5:检查是否有web worker任务,有的话就执行
6:执行队中新的宏任务,回到2,依次循环

源自:神三元——原生JS灵魂之问(下)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值