JavaScript引擎运行原理解析

1. 什么是JavaScript解析引擎?

简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序。比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2。

“JavaScript 引擎”通常被称作一种虚拟机。

JavaScript 虚拟机是一种进程虚拟机,专门设计来解释和执行的 JavaScript代码。
JavaScript 引擎的基本工作是把开发人员写的 JavaScript代码转换成高效、优化的代码,这样就可以通过浏览器进行解释甚至嵌入到应用中。每个JavaScript引擎都实现了一个版本的ECMAScript,JavaScript是它的一个分支。随着ECMAScript的不断发展,JavaScript引擎也不断改进。之所以有这么多不同的引擎,是因为它们每个都被设计运行在不同的web浏览器、headless浏览器、或者像Node.js那样的运行时环境中,它的唯一的目的就是读取和编译JavaScript代码。

常见的解析器:
在这里插入图片描述

1.解析引擎就是根据ECMAScript定义的语言标准来动态执行JavaScript字符串;
2.解析JS的过程分成两个阶段:语法检查阶段和运行阶段;
3.语法检查包括词法分析和语法分析,运行阶段又包括预解析和运行阶段(V8引擎会将JavaScript字符串编译成二进制代码,此过程应该归到语法检查过程中);
4.在JavaScript解析过程中,如遇错误就直接跳出当前代码块,直接执行下一个script代码段。所以在同一个script内的代码段有错误的话就不会执行下去,但是不会影响下一个script内的代码段。

第一阶段:语法检查

语法检查也是JavaScript解析器的工作之一,包括词法分析 和 语法分析,过程大致如下:

一:词法分析:JavaScript解释器先把JavaScript代码(字符串)的字符流按照ECMAScript标准转换为记号流

a = (b - c);

转换为记号流:

NAME "a"
EQUALS
OPEN_PARENTHESIS
 NAME "b"
MINUS 
NAME "c"
CLOSE_PARENTHESIS
SEMICOLON

二:语法分析:JavaScript语法分析器在经过词法分析后,将记号流按照ECMAScript标准把词法分析所产生的记号生成语法树。通俗地说就是把从程序中收集的信息存储到数据结构中,每取一个词法记号,就送入语法分析器进行分析。

语法分析不做的事:去掉注释,自动生成文档,提供错误位置(可以通过记录行号来提供)。
ECMAScript标准如下:

var,if,else,break,continue等是JavaScript的关键词
怎么样算是数字、怎么样算是字符串等等
定义了操作符(+,-,=)等操作符
定义了JavaScript的语法
定义了对表达式,语句等标准的处理算法,比如遇到==该如何处理

当语法检查正确无误之后,就可以进入运行阶段了。

第二阶段:运行阶段

一:预解析
第一步:创建执行上下文。解析器将语法检查正确后生成的语法树复制到当前执行上下文中。
第二步:属性填充。解析器会对语法树当中的变量声明、函数声明以及函数的形参进行属性填充。
预解析阶段创建的执行上下文包括:变量对象、作用域链、this
变量对象(Variable Object):由vardeclaration、function declaration(变量声明、函数声明)、arguments(参数)构成。变量对象是以单例形式存在。
作用域链(Scope Chain):variableobject + all parent scopes(变量对象以及所有父级作用域)构成。
this值:(thisValue):contentobject。this值在进入上下文阶段就确定了。一旦进入执行代码阶段,this值就不会变了。

栗子:

<script>
            console.log(a);
            var a = 1;
            function a(){console.log(2);}
            console.log(a);
            var a = 3;
            console.log(a);
            function a(){console.log(4);}
            console.log(a)
        </script>

第二行:会弹出functiona(){console.log(4);} ,因为预解析完成之后,被存进内存的a的值就是functiona(){console.log(4);}
第三行:第三行里有表达式,a被赋了一个新的值1表达式会改变变量的值。表达式可以改变预解析的值。
第四行:只是函数的声明,并没有用到表达式,而且也没有函数的调用,所以不会改变a的值。
第五行:因为a的值没有变化,所以还是1
第六行:使用了表达式,a被赋了一个新的值3
第七行:会弹出3
第八行:函数的声明,不会改变a的值。
第九行:a的值没有改变,所以还是3

为什么JavaScript是单线程?

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

任务队列

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。
在这里插入图片描述

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: UniApp 是一个使用 Vue.js 开发跨平台应用的框架。它的运行原理是基于 HBuilderX 编辑器将开发者编写的代码转换成原生平台的代码,然后运行在各个平台上。 首先,开发者使用 HBuilderX 编辑器创建一个 UniApp 项目,并选择所要开发的平台,如微信小程序、App、H5 等。然后,开发者使用 Vue.js 组件和语法编写应用的各个页面和功能。 UniApp 在编译的过程中,通过将开发者编写的代码转换为各个平台的运行代码,使得应用在不同平台上都能够正常运行。例如,对于微信小程序,UniApp 会将代码转换为符合微信小程序标准的 wxml、wxss 和 js 文件;对于 App,UniApp 会将代码转换为原生的 Android 或 iOS 代码。 UniApp 还提供了一套跨平台的 API,使得开发者能够方便地调用原生平台的功能和接口。比如,开发者可以使用 uni.request 方法来发起网络请求,无论是在微信小程序还是 App 中,都能够正常使用。 最后,UniApp 使用各个平台的打包工具将应用打包成可执行文件或可发布的代码文件。对于微信小程序,UniApp 会生成一个可以导入到微信开发者工具中预览和发布的项目文件夹;对于 App,UniApp 会生成原生的 Android 或 iOS 项目,开发者可以进行进一步的编译和发布。 综上所述,UniApp 的运行原理是将开发者编写的代码转换为各个平台的原生代码,并提供跨平台的 API,使得应用能够在不同平台上运行和发布。这种方式减少了开发者的工作量,提高了开发效率,使得开发跨平台应用变得更加简单和便捷。 ### 回答2: UniApp是一种基于Vue.js框架的跨平台开发解决方案,可以同时开发iOS、Android和Web应用。UniApp的运行原理主要是基于两个关键技术点:编译和渲染。 首先,UniApp应用在开发阶段使用Vue.js框架进行编写,开发者使用Vue的语法和相关技术进行业务和界面的构建。UniApp将Vue.js框架进行了扩展和适配,使其能够同时运行在不同的平台上。 在编译阶段,UniApp会将开发者编写的Vue代码转换为原生的JavaScript代码。它会根据应用的配置文件和平台的特性,进行相应的编译优化和转换。通过这个过程,UniApp将统一的Vue代码转换为特定平台的原生代码。 在渲染阶段,UniApp使用了各个平台自带的渲染引擎进行UI的渲染。对于iOS和Android,UniApp使用了各自的原生渲染引擎进行渲染;对于Web平台,UniApp使用了WebView进行渲染。UniApp将编译生成的原生代码交给相应的渲染引擎进行解析和渲染,最终呈现出用户界面。 除了编译和渲染外,UniApp还提供了一套统一的API和组件库。这些API和组件库可以在不同平台上实现一致的功能和样式,开发者可以直接调用这些API和组件进行业务的开发和界面的构建。 综上所述,UniApp的运行原理是通过编译和渲染来实现跨平台的应用开发。通过编译将统一的Vue代码转换为特定平台的原生代码,并使用各个平台的渲染引擎进行UI的渲染,最终实现在不同平台上运行的应用。这种原理使得开发者可以用一套代码同时开发多个平台的应用,提高了开发效率和代码复用性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值