Angualr中的AOT(Ahead-of-Time Compilation)编译(一)

来源:互联网 发布:数据分析工程师笔试题 编辑:程序博客网 时间:2024/05/21 09:34

--------------------------------------------------------------------------------------------------------------------------------------------

最近学习Angular2的内容,国内资料较少,发现一篇对于AOT讲的特别好文章,以备自己学习回顾。

尝试翻译如下。如有任何版权相关问题,请联系。如有翻译错误或不准确的地方欢迎大家留言,我会积极修正。

非专业,不喜勿喷。

作者:Minko Gechev

原文链接:http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/

--------------------------------------------------------------------------------------------------------------------------------------------

Angualr中的AOT(Ahead-of-Time Compilation)编译

作者写这篇文章的目的是因为该大牛为angular-seed (
关于angular-seed有仁兄已经写了博客,http://blog.csdn.net/ybdesire/article/details/50551486)框架添加了AOT,
导致有很多人提出了各种问题,然后作者详细解释了一下AOT的原理和用途。
主要有如下topic:
  • Angular中为什么需要编译?
  • 什么内容需要编译?
  • 如何进行编译?
  • 编译在什么时间点发生? Just-in-Time (JiT) vs Ahead-of-Time (AoT).
  • AOT有哪些优势?使用AOT我们能得到什么?
  • AOT编译是如何工作的,工作原理是什么?
  • 相对于JIT,使用AOT我们失去了哪些特性?

Angualr中为什么需要编译

简单来说:我们需要编译来达到更高效率的Angular程序。对于效率主要是指性能的改善,
但有时也带来带宽等方面的消耗。
AngularJS 1.x有渲染和变化检测的动态实现。例如,在AngularJS 1.x中的编译器是通用编译器。
它被设计用来执行任何模板的动态计算工作。虽然大多数情况下,它工作的特别好。因为动态特性,
导致JavaScript虚拟机(VM)只能进行较低层次的优化计算。
由于VM不知道对象的结构,提供脏检查逻辑(即scope)的上下文,它的内联高速缓存得到了大量
的失误,从而减慢执行速度。

Angualr2和以上版本,使用了不同的实现方式,不再为每一个单独的组件使用相同的逻辑执行渲染和变化检测,
该框架runtime或build生成VM友好或者说VM更加容易识别和优化的代码。这使得JavaScript虚拟机
能够更加快速的访问缓存和执行变化检测/渲染。

请看如下例子:
// ...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);  for (i = 0; i < this.$$children.length; i += 1) {    this.$$children[i].$digest();  }};// ...
上面代码来源于Angualr1.x的实现,上面我们在整个作用域树上进行深度优先搜索,寻找绑定的变化.。
这种方法将适用于任何指令。然而,与指令特定的代码相比,它明显运行速度较慢。
// ...var currVal_6 = this.context.newName;if (import4.checkBinding(throwOnChange, this._expr_6, currVal_6)) {    this._NgModel_5_5.model = currVal_6;    if ((changes === null)) {        (changes = {});    }    changes['model'] = new import7.SimpleChange(this._expr_6, currVal_6);    this._expr_6 = currVal_6;}this.detectContentChildrenChanges(throwOnChange);// ...
上面这段代码来自于Angualr-seed项目,用来实现生成detectChangesInternal的方法。它使用直接属性访问
获取单个绑定的值,并使用最有效的方法将它们与新值进行比较。一旦发现它们的值是不同的,它只更新
DOM元素的影响。

通过回答”为什么需要编译?“我们同时回答了“什么内容需要编译”。我们希望编译组件的模板(templates)
成为JavaScript的classes。这些类(classes)提供在绑定过程中检测变化的方法和渲染用户接口的方法。
通过这种方法,我们就不需要同底层平台存在联系(除了markup格式)。换句话说,通过实现不同的
渲染器(renderer),我们能够不需要任何代码修改使用同样AOT编译后的模块进行渲染。
这样的模块(component)能够被NativeScript渲染。例如:渲染器能够尽可能的理解传递的参数。

Just-in-Time (JiT) vs Ahead-of-Time (AoT)

这一节同时包含编译在什么时间点发生?”的答案。
Anuglar的编译器比较cool的是可以在runtime(如用户的browser中)引入也可以build时点
(作为build流程的一部分)引入。
由于Angualr的便携性,我们可以在任何Javascript VM上运行我们的framework。那么我们
为什么不让Angular的编译器同时运行在browser和node上呢?

JIT编译中的事件流(event flow)

没有AOT时我们典型的开发流程:
  • 使用TypeScript开发Angular应用
  • 使用Tsc编译我们的应用
  • 打包(Bundling
  • 压缩最小化(Minification
  • 发布(Deployment
当用户打开浏览器查看我们已经部署的应用时,他将经历如下步骤(不包含内容安全策略(CSP)):
  • 下载JavaScript资源(assets)
  • Angular渲染页面(Angular bootstraps
  • Augular进行JIT编译过程,生成我们每个模块的JavaScript。
  • 应用被渲染(rendered)完成,展示给用户

AOT编译中的事件流(event flow)

使用AOT,经历如下步骤:

  • 使用TypeScript开发Angular应用
  • 使用ngc编译我们的应用.
    • 使用Angular编译器将模板(templates)编译成通常的TypeScript。
    • 将TypeScript编译JavaScript.
  • 打包(Bundling
  • 压缩最小化(Minification
  • 发布(Deployment

尽快看起来我们有更多的编译过程,但是对于用户来说,他只需要经历如下步骤:

  • 下载JavaScript资源(assets)
  • Angular渲染页面(Angular bootstraps
  • 应用被渲染(rendered)完成,展示给用户

我们可以看到对于用户来说,AOT编译使得第三部消失了。这就意味着更好更快的用户体验(UX)。
并且我们已经有软件支持自动编译了。NB如angular-seedangular-cli

综上所述,我们可以看出Angualr中JIT同AOT编译的主要不同点:

  • 编译选择的位置不同

  • JIT生成JavaScript(TypeScript没太关注这部分因为代码需要在浏览器被编译为JavaScript)。
    AoT生成TypeScript.

下一遍将更加深入的分析AOT,敬请期待。




0 0
原创粉丝点击