Angular 2 JIT vs AOT
在 Angular 应用程序中,包含了我们通过 Angular 提供的 API 实现的自定义指令。这些自定义指令对浏览器来说,都是无法识别的,因此每个 Angular 应用程序在运行前,都需要经历一个编译的阶段。 在 Angular 2 中有两种编译模式:
JIT - Just-In-Time
Just-in-Time 编译模式开发流程
应用部署后,当用户通过浏览器访问我们应用的时候,她将经历以下步骤(非严格 CSP):
AOT - Ahead-Of-Time
Ahead-Of-Time 编译模式开发流程
应用部署后,相比于 JIT 编译模式,在 AOT 模式下用户访问我们的应用,只需经历以下步骤:
JIT vs AOTJust-In-Time (JIT) compilation
Ahead-Of-Time (AOT) compilation
除此之外 AOT 还有以下优点:
另外感兴趣的读者,可以使用 source-map-explorer 工具查看不同模式下生成的 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 在项目根目录新增 { "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 编译:
命令成功运行后,在根目录下会自动生成 *.component.ngfactory.ts 此类文件内包含以下定义:
上面的 {COMPONENT} 表示组件关联的类名称,{COUNTER} 是一个无符号整数。 它们都继承于 AppView 并实现以下方法:
其中 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.使用 示例项目:
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') }) ] }; 示例项目:
3.使用 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(),'src/app/modules/main.module#MainModule') }) ] }; 示例项目:
参考资源
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |