angular2 JIT and AOT

为什么需要编译

Angular应用中包含的组件、HTML模板(比如:@Directive、@Component、@NgModule、@Pipe)很多都是JS VM无法解析的,所以在浏览器渲染应用之前,组件和模板必须要被Angular编译器转换为可以执行的JavaScript。

angular2编译模式

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

  • JIT - Just-In-Time
  • AOT - Ahead-Of-Time

JIT事件流:
开发流程:

  • 使用TypeScript开发Angular应用(此处以ts举例)
  • tsc编译
  • 构建
  • 压缩
  • 部署

用户打开浏览器,他将经历以下步骤 (没有严格的CSP):

  • 下载所有的JavaScript资源
  • 启动Angular
  • 通过JIT 编译处理生产js代码
  • 渲染应用


    angular2 JIT and AOT_第1张图片

AOT事件流:

  • 使用Typescript开发Angular 应用
  • 使用 ngc来编译应用(目前的ngc编译报错还不太好用,angular团队正在用tsc的方式进行优化,据说很快就会发包)
  • 模板会被ngc编译成TypeScript文件(通常是)
  • TypeScript编译为JavaScript代码
  • 构建
  • 压缩
  • 部署

用户打开浏览器,他将经历以下步骤:

  • 下载所有的资源
  • 启动Angular
  • 渲染应用


    angular2 JIT and AOT_第2张图片

aot将compile的过程放在应用部署前,所以浏览器端承载的工作量就会大幅度减少,相应的页面加载时间也会大幅度减少,这也就意味着更快更好的用户体验。

JIT vs AOT:

编译方式 编译时机 构建速度 打包大小 性能/渲染速度 模板错误检查时间 安全性
JIT app运行时 - - app运行时
AOT app构建阶段 - 更快 app构建阶段

AOT优势:

  • 渲染得更快
    使用AOT,浏览器下载预编译版本的应用程序。 浏览器直接加载运行代码,所以它可以立即渲染该应用,而不用等应用完成首次编译,我们两个项目AOT加载速度相比JIT有3-5倍的提高

  • 需要的异步请求更少
    编译器把外部HTML模板和CSS样式表内联到了该应用的JavaScript中。 消除了用来下载那些源文件的Ajax请求。

  • 需要下载的Angular框架体积更小
    如果应用已经编译过了,自然不需要再下载Angular编译器了。 该编译器差不多占了Angular自身体积的一半儿,所以,省略它可以显著减小应用的体积。但是angular采用 Code Generation 的方式,生成的 ts/js 代码肯定是会比原来的 html 的文件大小要大的,所以在应用足够大(模版足够多)的情况下 AOT 的大小是可以反超 JIT 的大小的,很不幸,我们项目就是如此

  • 提早检测模板错误
    AOT编译器在构建过程中检测和报告模板绑定错误,避免用户遇到这些错误。

  • 更安全
    AOT编译远在HTML模版和组件被服务到客户端之前,将它们编译到JavaScript文件。没有模版可以阅读,没有高风险客户端HTML或JavaScript可利用,所以注入攻击的机会较少

JIT优势:
编译时间短,除非确实有动态组件的需求,否则jit唯一的优势就是能用来做在线 Demo和开发调试,参考知乎答案

我们两个项目AOT和JIT对比效果:
项目A:

编译方式 打包大小 渲染速度
JIT 5.86M
angular2 JIT and AOT_第3张图片
AOT 10.8M
angular2 JIT and AOT_第4张图片

项目B:

编译方式 打包大小 渲染速度
JIT 4.12M
angular2 JIT and AOT_第5张图片
AOT 6.21M
angular2 JIT and AOT_第6张图片

官方在View 和 DI 上了 View Engine 后aot编译后没有太多静态文件了,目前aot的编译大小已经低于jit(2017/10/19更新)

懒加载

懒加载也叫延迟加载,即在需要的时候进行加载,随用随载

在单页面应用中,如果没有应用懒加载,进入首页时会导致需要加载的内容过多,延时过长,不利于用户体验

运用懒加载将页面进行划分,按需加载页面,可以分担首页所承担的加载压力,减少加载用时

如果对首屏启动有更严格的要求,最好采用服务端渲染

angular2懒加载可以参考官方文档

摇树优化:

作用:消除unused code
原理:通过跟踪import和export语句进行静态分析,排除那些被导出过但又从未被导入的代码(ES6 modules 的静态特性)

目前大部分工具只能对ES2015模块摇树,因为那里有import和export语句,所以需要将ts编译成es2015(通过tsconfig配置实现)

  • 摇树优化详细介绍可以参考angular官方文档
  • gulp+rollup摇树优化可以参考angular-seed
  • webpack2自带了tree-shaking,配置可以参考工程angular-starter
  • angular-cli搭建工程:推荐使用,已经帮你集成,不需要再去繁琐配置各种打包摇树优化等

webpack2的摇树和rollup摇树区别可以参考知乎上这个回答

webpack2注意事项

项目目前使用的是webpack2,总结了下开发过程中遇到的坑:

  • ngc-webpack不要设置resourceOverride,否则打包后的图片url等会有问题
  • "JavaScript heap out of memory"可以通过设置node参数 node --max_old_space_size=4096(如不管用,参数可以设置更大试试)
  • typescript使用2.0以上版本(摇树需要)
  • 使用awesome-typescript-loader包的2.x及以上版本(摇树需要)
  • 保证我们的应用和Angular2库代码在同一个位置(摇树需要)
  • UglifyJsPlugin压缩代码, Webpack2可以删除Bundle中未使用的引用代码,但不会从Bundle中删除未使用的代码,在这种情况下就需要使用UglifyJsPlugin,它能够智能的移除未使用的代码
  • 使用AOT在build时,浏览器渲染快,但是在模板足够多的情况下大于jit打包体积,配合gzip使用最佳,项目使用的是nginx,gzip在nginx详细配置可参考这篇文章

AOT注意事项

由于AoT的特性,部分在JIT模式下可用的方法在AoT下是不可行或者官方不建议的,开发代码的童鞋在aot模式下需要注意额外注意这些情况,github上8000+star的angular-starter工程总结如下(英文捉急,就不在这献丑翻译了):

  • Don’t use require statements for your templates or styles, use styleUrls and templateUrls, the angular2-template-loader plugin will change it to require at build time.
  • Don’t use default exports.
  • Don’t use form.controls.controlName, use form.get(‘controlName’)
  • Don’t use control.errors?.someError, use control.hasError(‘someError’)
  • Don’t use functions in your providers, routes or declarations, export a function and then reference that function name
  • @Inputs, @Outputs, View or Content Child(ren), Hostbindings, and any field you use from the template or annotate for Angular should be public

补充一些我们项目开发过程中遇到的问题,O(∩_∩)O 都是开发时代码不规范埋下的坑:

  • 定义的函数传参必须匹配
  • 等和非等判断类型必须一致
  • 未在ts定义的变量不要在html模板中使用

总结

推荐大家在dev时使用jit可以提高开发调试效率,在prod时使用aot

参考:
http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/
http://blog.rangle.io/optimize-your-angular2-application-with-tree-shaking/

你可能感兴趣的:(angular2 JIT and AOT)