В чем разница между Angular AOT и JIT-компилятором

я погружаюсь в angular 4, и я пытаюсь понять компиляцию. Я читал, что AOT и JIT оба компилируют TypeScript в JavaScript, будь то на стороне сервера или на стороне клиента. Если я компилирую его, когда я создаю его с помощью Webpack и grunt и развертываю этот мини-javascript, как AOT и JIT даже входят в картину?

3 ответов


Я читал, что AOT и JIT оба компилируют TypeScript в JavaScript будь то на стороне сервера или на стороне клиента.

нет, это не то, что делают компиляторы AOT и JIT. TypeScript транспилируется в JavaScript с помощью компилятора typescript.

Угловое компилятор

есть два компилятора, которые выполняют тяжелую работу компиляции и генерации кода:

компилятор представления компилирует шаблоны компонентов и генерирует view factories. Он анализирует выражения и html-элементы внутри шаблона и проходит через многие стандартные фазы компилятора:

parse-tree (lexer) -> abstract-syntax-tree (parser) -> intermediate-code-tree -> output

компилятор провайдера компилирует провайдеров модулей и генерирует модуль фабрики.

JIT vs AOT

эти два компиляторы используются как в JIT, так и в компиляции AOT. Компиляции JIT и AOT отличаются тем, как они получают метаданные, связанные с компонентом или модулем:

// the view compiler needs this data

@Component({
   providers: ...
   template: ...
})

// the provider compiler needs this data

@NgModule({
   providers: ...
});

компилятор JIT использует среду выполнения для получения данных. Функции декоратора @Component и @NgModule выполнены и они придают метаданных к компоненту или классу модуля, который позже читается угловыми компиляторами с использованием отражающих capabiliteis (Reflect library).

компилятор AOT использует статический код анализ, предоставляемый компилятором typescript для извлечения метаданных и не зависит от оценки кода. Следовательно, он немного ограничен по сравнению с JIT-компилятором, поскольку он не может оценивать явный код-например, он требует экспорта функции:

// this module scoped function

function declarations() {
  return [
    SomeComponent
  ]
}

// should be exported

export function declarations() {
  return [
    SomeComponent
  ];
}
@NgModule({
  declarations: declarations(),
})
export class SomeModule {}

опять же, компиляторы JIT и AOT в основном являются оболочками для извлечения метаданных, связанных с компонентом или модулем, и они оба используют базовый вид и компилятор поставщика для создания фабрик.

Если Я компилирую его, когда я создаю его с помощью Webpack и grunt и развертывание этого уменьшенного javascript, как AOT и JIT даже входят фотографию?

Угловое обеспечивает плагин webpack который выполняет транспиляцию из typescript во время сборки. Этот плагин также может скомпилировать ваш проект, чтобы вы не включали JIT-компилятор в пакет и не выполняли компиляцию на клиенте.


прежде всего угловой уходит от компиляции JIT. Надеюсь, мы увидим это в angular@5.x.x

угловой компилятор принимает все метаданные, которые вы пишете, используя декораторы, такие как

@Component({
  selector: 'my-app',
  template: '<h1>Hello</h1>'m
  styles: [ ':host { display: block }' ]
})

constructor(
  @Host() @Optional() private parent: Parent,
  @Attribute('name') name: string) {} 

@ViewChild('ref') ref;

@ContentChildren(MyDir) children: QueryList<MyDir>;  

@HostBinding('title') title;

@HostListener('click') onClick() { ... }

// and so on

и анализирует его. Затем он берет шаблон и таблицы стилей и анализирует их. Компилятор проходит много шагов, которые я не буду описывать здесь. Вы можете взглянуть на Следующая страница это описывает процесс компиляции. Существует также большой разговор Тобиас Босх. Наконец, компилятор создает ngfactories для создания экземпляра нашего приложения.

я думаю, что основные различия между AOT в JIT являются

  • когда и где angular запускает компиляцию
  • как компилятор собирает метаданные
  • какой формат ngfactory что компилятор выдает

JIT-компилятор

работает на стороне клиента в нашем браузере на каждой странице загрузки.

он собирает метаданные с помощью ReflectionCapabilities API С @angular/core пакета. У нас есть следующие опции для работы с метаданными в режиме JIT:

1) Прямой API

например, мы можем объявить наш компонент, как

export class AppComponent {
  static annotations = [
    new Component({
      selector: 'my-app',
      templateUrl: `./app.component.html`,
      styles: [ ':host { display: block }' ]
    })
  ];

  test: string;

  static propMetadata = {
      test: [new HostBinding('title')]
  };


  ngOnInit() {
    this.test = 'Some title'
  }
}

подобный код мы можем написать в ES5. JIT-компилятор будет читать annotations и propMetadata статические свойства. Компилятор AOT не будет работать с ним.

2) tsickle В API

export class AppComponent {
  static decorators = [{
      type: Component,
      args: [{
        selector: 'my-app',
        templateUrl: `./app.component.html`,
        styles: [ ':host { display: block }' ]
      },]
  }];

  test: string;

  static propDecorators = {
    'test': [{ type: HostBinding, args: ['title'] }]
  };

  ngOnInit() {
    this.test = 'Some title'
  }
}

приведенный выше код обычно генерируется некоторыми библиотеке. Угловой пакет также имеет такой же формат. Это также не будет работать с АОТ. Мы должны отправить metadata.json файл с нашей библиотекой для компиляции AOT.

3) Получение метаданных, созданных путем вызова декораторов

@Component({
  selector: 'my-app',
  templateUrl: `./app.component.html`
})
export class AppComponent {
  @HostBinding('title') test = 'Some title';
}

компилятор Typescript преобразует предыдущий код в

 var AppComponent = (function () {
    function AppComponent() {
        this.test = 'Some title';
    }
    return AppComponent;
}());
__decorate([
    HostBinding('title')
], AppComponent.prototype, "test", void 0);
AppComponent = __decorate([
    Component({
        selector: 'my-app',
        templateUrl: "./app.component.html"
    })
], AppComponent);

этот код выполняется в режиме JIT так угловой вызовы компонент декоратор!--34-->

const TypeDecorator: TypeDecorator = <TypeDecorator>function TypeDecorator(cls: Type<any>) {
      // Use of Object.defineProperty is important since it creates non-enumerable property which
      // prevents the property is copied during subclassing.
      const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
          (cls as any)[ANNOTATIONS] :
          Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
      annotations.push(annotationInstance);
      return cls;
};

сегодня больше не использует Reflect api. Компилятор считывает данные непосредственно из __annotations__ свойства

if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
  return (typeOrFunc as any)[ANNOTATIONS];
}

JIT-компилятор производит javascript ngfactories

компилятор AOT

работает на стороне сервера (nodejs) во время сборки с помощью ngc.

С AOT нет шага компиляции во время выполнения. Когда мы запускаем наше приложение в браузере мы уже прекомпилированные ngfactories. Это дает нам лучшую производительность сначала и ленивую нагрузку. Мы также не грузим @angular/compiler код в нашем производственном комплекте больше. Но наш пучок может значительно вырасти из-за нашего ngfactories код.

компилятор AOT использует машинопись с API для анализа кода typescript. Для получения метаданных компилятор проходит через StaticSymbolResolver и MetadataCollector API-интерфейсы.

так что это занимает и создает объектную модель typescript. Так наши AppComponent класс будет представлен как NodeObject С типом 229 (ClassDeclaration)

enter image description here

как мы видим этот объект имеет decorators свойства

enter image description here

и специальная обертка для машинописи, написанная угловой командой и называемая tsc-wrapper делает тяжелую работу для извлечения этих метаданных.

когда компилятор отвечает он пытается получить метаданные из metadata.json:

if (DTS.test(filePath)) {
  var metadataPath = filePath.replace(DTS, '.metadata.json');
  if (this.context.fileExists(metadataPath)) {
    return this.readMetadata(metadataPath, filePath);
  }
  else {
    // If there is a .d.ts file but no metadata file we need to produce a
    // v3 metadata from the .d.ts file as v3 includes the exports we need
    // to resolve symbols.
    return [this.upgradeVersion1Metadata({ '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)];
  }
}

и, наконец, компилятор AOT использует TypeScriptEmitter to производить typescript ngfactories (угловые

см. также


после загрузки браузером пакетов приложений угловой компилятор (упакованный внутри поставщика.пачка.js) выполняет компиляцию шаблонов из main.пачка.js. Это называется компиляцией Just-in-Time. Этот термин означает, что компиляция происходит во время прибытия пакетов в браузер.

недостатками компиляции JIT являются:

  1. существует временной промежуток между загрузкой пакетов и отображением пользовательского интерфейса. Это время тратится на JiT сборник. На маленьком приложении это время минимально, но в больших приложениях компиляция JiT может занять пару секунд, поэтому пользователю нужно ждать дольше, чтобы просто увидеть ваше приложение.

  2. угловой компилятор должен быть включен в поставщика.пачка.js, который добавляет к размеру вашего приложения.

использование компиляции JiT в prod не рекомендуется, и мы хотим, чтобы шаблоны были предварительно скомпилированы в JavaScript до создания пакетов. Этот это то, о чем идет компиляция Ahead-of-Time (AoT).

преимущества компиляции AoT:

  1. браузер может отображать пользовательский интерфейс, как только приложение загружается. Нет необходимости ждать компиляции кода.

  2. компилятор ngc не входит в состав поставщика.пачка.js и результирующий размер вашего приложения могут быть меньше.

Если вы используете Webpack, чтобы сделать AoT, вам нужно вызвать ngc компилятор. Например:

"build:aot": "ngc -p tsconfig.json && webpack --config webpack.config.js"