转载于:https://segmentfault.com/a/1190000008739157

在 Angular 应用程序中,包含了我们通过 Angular 提供的 API 实现的自定义指令。这些自定义指令对浏览器来说,都是无法识别的,因此每个 Angular 应用程序在运行前,都需要经历一个编译的阶段。

在 Angular 2 中有两种编译模式:

  • JIT - Just-In-Time

  • AOT - Ahead-Of-Time

JIT - Just-In-Time

Just-in-Time 编译模式开发流程

  • 使用 TypeScript 开发 Angular 应用

  • 运行 tsc 编译 TypeScript 代码

  • 使用 Webpack 或 Gulp 等其他工具构建项目,如代码压缩、合并等

  • 部署应用

应用部署后,当用户通过浏览器访问我们应用的时候,她将经历以下步骤(非严格 CSP):

  • 下载应用相关的资源,如 JavaScript 文件、图片、样式资源

  • Angular 启动

  • Angular 进入 JiT 编译模式,开始编译我们应用中的指令或组件,生成相应的 JavaScript 代码

  • 应用完成渲染

AOT - Ahead-Of-Time

Ahead-Of-Time 编译模式开发流程

  • 使用 TypeScript 开发 Angular 应用

  • 运行 ngc 编译应用程序

    • 使用 Angular Compiler 编译模板,一般输出 TypeScript 代码

    • 运行 tsc 编译 TypeScript 代码

  • 使用 Webpack 或 Gulp 等其他工具构建项目,如代码压缩、合并等

  • 部署应用

应用部署后,相比于 JIT 编译模式,在 AOT 模式下用户访问我们的应用,只需经历以下步骤:

  • 下载应用相关的资源,如 JavaScript 文件、图片、样式资源

  • Angular 启动

  • 应用完成渲染

JIT vs AOT

Just-In-Time (JIT) compilation

Ahead-Of-Time (AOT) compilation

特性 JIT AOT
编译平台 (Browser) 浏览器 (Server) 服务器
编译时机 Runtime (运行时) Build (构建阶段)
包大小 较大 较小
执行性能 - 更好
启动时间 - 更短

除此之外 AOT 还有以下优点:

  • 在客户端我们不需要导入体积庞大的 angular 编译器,这样可以减少我们 JS 脚本库的大小

  • 使用 AOT 编译后的应用,不再包含任何 HTML 片段,取而代之的是编译生成的 TypeScript 代码,这样的话 TypeScript 编译器就能提前发现错误。总而言之,采用 AOT 编译模式,我们的模板是类型安全的。

另外感兴趣的读者,可以使用 source-map-explorer 工具查看不同模式下生成的 bundle JS 文件中各种 JS 资源的占比。

AOT详解

app.component.html

<button (click)="toggleHeading()">Toggle Heading</button>
<h1 *ngIf="showHeading">Hello {{name}}</h1><h3>List of Heroes</h3>
<div *ngFor="let hero of heroes">{{hero}}</div>

app.component.ts

import { Component } from '@angular/core';@Component({moduleId: module.id,selector: 'my-app',templateUrl: './app.component.html'
})
export class AppComponent {name: string = 'Angular';showHeading = true;heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado'];toggleHeading() {this.showHeading = !this.showHeading;}
}

安装 npm 依赖:

npm install @angular/compiler-cli @angular/platform-server --save

在项目根目录新增 tsconfig-aot.json 配置文件,内容如下:

{"compilerOptions": {"target": "es5","module": "es2015","moduleResolution": "node","sourceMap": true,"emitDecoratorMetadata": true,"experimentalDecorators": true,"lib": ["es2015", "dom"],"noImplicitAny": true,"suppressImplicitAnyIndexErrors": true},"files": ["src/app/app.module.ts","src/main.ts"],"angularCompilerOptions": {"genDir": "aot","skipMetadataEmit" : true}
}

执行 AoT 编译:

  • node_modules/.bin/ngc -p tsconfig-aot.json

  • "node_modules/.bin/ngc" -p tsconfig-aot.json # Windows 用户

命令成功运行后,在根目录下会自动生成 aot 目录,接下来我们来研究一下目录中生成的文件:

*.component.ngfactory.ts

此类文件内包含以下定义:

  • View_{COMPONENT}_Host{COUNTER} - 内部宿主组件

  • View_{COMPONENT}{COUNTER} - 内部组件

上面的 {COMPONENT} 表示组件关联的类名称,{COUNTER} 是一个无符号整数。

它们都继承于 AppView 并实现以下方法:

  • createInternal - 用于渲染组件

  • destroyInternal - 用于执行清理操作,如移除事件监听、销毁内嵌视图

  • detectChangesInternal - 用于执行变化检测

其中 detectChangesInternal 方法中包含了 JavaScript VM Friendly 的代码,现在我们来看一下具体示例:

<h1 *ngIf="showHeading">Hello {{name}}</h1>

该模板编译后,detectChangesInternal 方法中的代码如下:

 detectChangesInternal(throwOnChange:boolean):void {// 计算h1标签中文本元素的内容const currVal_2:any = import3.inlineInterpolate(1,'Hello ' ,this.parentView.context.name,'');// 判断新值与旧值是否相等,若不相等则更新文本的内容,同时设置旧值为当前值if (import3.checkBinding(throwOnChange,this._expr_2,currVal_2)) {this.renderer.setText(this._text_1,currVal_2);this._expr_2 = currVal_2;}}

接下来我们来看一下 Angular 1.x 中简易版 $digest :

// $scope.$watch('name', function(newValue, oldValue) {})
Scope.prototype.$watch = function (exp, fn) {'use strict';this.$$watchers.push({exp: exp,fn: fn,last: Utils.clone(this.$eval(exp))});
};Scope.prototype.$digest = function () {'use strict';var dirty, watcher, current, i;do {dirty = false; for (i = 0; i < this.$$watchers.length; i += 1) {watcher = this.$$watchers[i]; current = this.$eval(watcher.exp); // 计算新值if (!Utils.equals(watcher.last, current)) { // 比较新值和旧值watcher.last = Utils.clone(current); // 保存新值,用于下一次比较dirty = true;watcher.fn(current);}}} while (dirty); // 在Angular1.x的源码中会有TTL值控制最大的检测次数,避免出现死循环for (i = 0; i < this.$$children.length; i += 1) {this.$$children[i].$digest();}
};

从上面的代码可以看出,Angular 1.x 中变化检测涉及循环遍历比 Angular 2 的变化检测逻辑复杂很多。此外 Angular 2 的变化检测是单向的,从根组件开始执行,具体如下图:

更令人兴奋的是,我们还可以灵活地设置 ChangeDetectionStrategy (变化检测策略) 来进一步提供应用的性能。

AOT实战

1.使用 ngc 命令行工具

示例项目:

  • ngc + Webpack

  • ngc + Rollup

  • ngc + library generation

2.使用 @ngtools/webpack Webpack 2 插件

webpack.config.js 配置:

'use strict';
let path = require('path');
let AotPlugin = require('@ngtools/webpack').AotPlugin;module.exports = {module: {rules: [{ test: /\.ts/, use: '@ngtools/webpack' }]},plugins: [new AotPlugin({tsConfigPath: path.join(process.cwd(), 'tsconfig.json'),entryModule: path.join(process.cwd(), 'src/app/modules/main.module#MainModule')})]
};

示例项目:

  • Webpack 2 + plugin

  • Angular CLI

3.使用 @ultimate/aot-loader Webpack 2 插件

webpack.config.js 配置:

'use strict';
let path = require('path');
let AotPlugin = require('@ultimate/aot-loader').AotPlugin;module.exports = {module: {rules: [{ test: /\.ts/, use: '@ultimate/aot-loader' }]},plugins: [new AotPlugin({tsConfig: path.join(process.cwd(), 'tsconfig.json'),entryModule: path.join(process.cwd(), 'src/app/modules/main.module#MainModule')})]
};

示例项目:

  • Webpack 2 + plugin

参考资源

  • angular cookbook aot-compiler

  • Ahead-of-Time Compilation in Angular

  • Multiple solutions for Angular Ahead of Time (AOT) Compilation

Angular 2 JIT vs AOT相关推荐

  1. angular jit and aot

    为什么需要编译 Angular应用中包含的组件.HTML模板(比如:@Directive.@Component.@NgModule.@Pipe)很多都是JS VM无法解析的,所以在浏览器渲染应用之前, ...

  2. JIT和AOT编译详解

    JIT和AOT编译介绍 JIT - Just-In-Time             实时编译,即时编译 通常所说的JIT的优势是Profile-Based Optimization,也就是边跑边优化 ...

  3. JIT VS AOT

    一.AOT,JIT是什么 JIT,即Just-in-time,动态(即时)编译,边运行边编译:AOT,Ahead Of Time,指运行前编译,是两种程序的编译方式 理解 jit.aot 程序主要有两 ...

  4. aot android,android – JIT与AOT编译

    我不是完全家喻户晓的,如何在实践中 Android上的Dalvik JIT工作,因为JIT有几个选择可以如何工作. 第一个选择是,在应用程序启动时,JIT将所有字节码转换为CPU指令.此选项在应用程序 ...

  5. 【JAVA】JIT和AOT

    JIT和AOT 目前,程序主要有两种运行方式:静态编译与动态解释. 静态编译的程序在执行前全部被翻译为机器码,通常将这种类型称为AOT (Ahead of time)即 "提前编译" ...

  6. Java在云原生的破局利器——AOT(JIT与AOT)

    导读 JIT(Just-in-Time,实时编译)一直是Java语言的灵魂特性之一,与之相对的AOT(Ahead-of-Time,预编译)方式,似乎长久以来和Java语言都没有什么太大的关系.但是近年 ...

  7. Angular 的 预先(AOT)编译器

    预先编译器, 英文全称是 Ahead-of-time compiler.由于 Angular 9 新版本的到来,CLI 应用程序默认情况下以 AOT 模式进行编译,其中包括模板类型检查,因此,我觉得有 ...

  8. ART、JIT、AOT、Dalvik之间有什么关系?

    2019独角兽企业重金招聘Python工程师标准>>> JIT与Dalvik JIT是"Just In Time Compiler"的缩写,就是"即时编 ...

  9. android将引入aot编译器,JIT与AOT编译模式

    JIT,即Just-in-time,动态(即时)编译,边运行边编译: AOT,Ahead Of Time,指运行前编译,是两种程序的编译方式 JIT ​ JIT,即"Just In Time ...

最新文章

  1. 【组队学习】【28期】Datawhale组队学习内容介绍
  2. java学习笔记(八)----包,jar文件
  3. 【2019牛客暑期多校训练营(第三场)- B】Crazy Binary String(思维,01串,前缀和)
  4. UILabel 宽高自适应
  5. c语言枚举法求满射函数,实变函数论讲义
  6. seaborn—sns.scatterplot绘制散点图
  7. java cpu_JAVA定位CPU占用率高
  8. c语言小游戏百度云资源,c语言小游戏合集
  9. 《Python源码剖析》.pdf
  10. Ubuntu16.04常用工具
  11. java车机_真·车载版Android来了:车机实现全部功能
  12. 微信公众平台开发(1)验证TOKEN源码
  13. 国仁老猫:电商直播与普通直播有什么区别,新手该如何做好电商直播。
  14. 学籍管理系统源代码java_java学籍管理系统完整版.zip
  15. 告诉你喝水的14个惊人真相
  16. 实地地产借助联想企业网盘构建信息化,重塑地产行业新未来
  17. 性格测试小软件有哪些,十个有趣的性格小测试 测试你是什么性格
  18. 上海大学计算机学院邢稹,【CES·毕业季】学霸寝室||相约一起“上岸”,我们是最亲密的战友!...
  19. 『数据稽核』的相关知识
  20. matlab学习记录

热门文章

  1. Akka并发编程——第三节:Actor模型(二)
  2. HTTP访问一个网站的过程详解
  3. css_04 | CSS——CSS 值和单位
  4. Android组件化开发实践(九):自定义Gradle插件
  5. python json模块 超级详解
  6. [Linux基础环境/软件]Linux下安装resin web服务器(涉及gcc、jdk环境部署)
  7. Eclipse创建java webproject配置Tomacat和JDK
  8. android dialog加载中动画效果
  9. 网络实验环境搭建--1.工具及搭建思路
  10. How to Create a Development Package ?