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

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

最近学习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,敬请期待。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值