当前位置: 首页 > 科技观察

前端框架的JIT和AOT傻傻分不清楚

时间:2023-03-14 14:33:57 科技观察

大家好,我是Kason。现代前端框架都需要“编译”这个步骤,用于:将框架中描述的UI转化为宿主环境可以识别的code代码转换,比如将ts编译成js,实现polyfill等,进行一些编译时优化的代码打包,压缩和混淆编译可以分两次执行:在构建代码时,称为AOT(AheadOfTime,提前或预编译)。宿主环境获取的是编译后的代码。当代码在宿主环境中执行时,称为JIT(JustInTime,即时编译),代码在宿主环境中编译和执行。本文将谈谈两者的区别以及AOT在前端框架中的应用。AOT和JIT的区别Angular同时提供了这两种编译方案。下面以Angular为例来说明两者的区别。考虑以下Angular代码:import{Component}from"@angular/core";@Component({selector:"app-root",template:"

{{getTitle()}}}

"})exportclassAppComponent{publicgetTitle(){return'HelloWorld';}}定义了AppComponent,浏览器(作为宿主环境)的最终渲染结果为:现在将模板中使用的getTitle方法修改为undefinedgetTitleXXX://来自模板:"

{{getTitle()}}

"//换成模板:"

{{getTitleXXX()}}

"如果使用AOT,之后会立即报错编译:组件AppComponent模板出现ERROR。如果使用JIT,编译后不会报错,在浏览器中执行代码时会报错:ERRORTypeError:_co.getTitleXXXisnotafunction造成以上差异的原因是:使用JIT时,构建阶段只是使用tsc将ts编译成js并打包代码。打包后的代码在浏览器运行后,当装饰器(上例中的@Component语句)执行时,Angular的模板编译器开始编译模板字段中包含的模板语法,并报错。使用AOT时,tsc和Angular的模板编译器会在构建阶段进行编译,因此模板字段中包含的错误会被立即发现。除了以上区别,JIT和AOT的区别还包括:使用JIT的应用在第一次加载时比AOT慢,因为需要先编译代码,而使用AOT的应用已经编译完成Angular的应用程序代码量通常比使用AOT的应用程序大,因为在运行时会有更多的编译代码。基于以上原因,在Angular中,开发环境一般采用JIT,生产环境采用AOT。从前端框架的角度,AOT可以分两步描述前端框架的工作原理:根据组件状态变化找到变化的UI,将变化的UI渲染为宿主环境的真实UI.步骤1开销。这是大多数使用模板语法描述UI的前端框架都会进行的优化,例如Vue3、Angular和Svelte。本质原因是模板语法的写法是固定的,固定就是“可分析”的意思。“Analyzable”是指编译时可以标记模板语法中的静态部分(不变部分)和动态部分(包括自变量和可变部分),这样在寻找变化的UI部分时,步骤1可以跳过static。甚至Svelte和Solid.js在编译时直接使用AOT来建立“组件状态和UI的动态部分之间的关??系”。运行时,组件状态发生变化后,可以直接执行步骤2。AOT和JSX使用JSX描述UI的前端框架很难从AOT中获益。原因是JSX是ES的语法糖。作为JS语句,只有执行后才能知道结果,很难静态分析。为了让使用JSX在AOT中描述UI的前端框架受益,有两种思路:使用新的AOT思路限制JSX的灵活性React尝试了第一种思路。prepack是meta(原Facebook)推出的实现AOT优化的React编译器。他的想法是改变源代码的运行逻辑,输出更高性能的代码,同时保持运行结果的一致性。即:代码在编译时将计算结果保存在编译后的代码中,而不是在运行时对其求值。例如以下代码:(function(){functionhello(){return'hello';}functionworld(){return'world';}global.s=hello()+''+world();})();使用prepack编译后的输出:s="helloworld";不幸的是,出于复杂性和劳动力成本的考虑,prepack项目在三年前就被搁置了。Solid.js还使用JSX来描述视图。它实现了几个内置组件来描述UI的逻辑,从而降低了JSX的灵活性,使AOT成为可能。例如:For替换一个数组的map方法:Loading...
}>{(item)=>
{item}div>}Showreplacesif条件语句:0}fallback={
Loading...
}>
MyContent
总结首先,前端框架可以从AOT中获得很多好处,其中最重要的是:减少“根据组件状态变化找到变化的UI”这一步的工作量。AOT的前提是:组件代码易于分析。