角度改善大组件加载时间

时间:2017-08-23 18:14:26

标签: angular typescript components

我有一个非常大的组件,可以加载超过1000个数据元素。这些数据元素通过服务填充,该服务仅被调用一次。在最初的实现中,每次初始化组件时都会调用该服务,这是我认为问题所在。因此,我创建了一个只在祖父组件中调用一次的共享服务。

组件层次结构如下:

  • AddComponent(祖父母)
    • Type1AddComponent
      • BlockComponent(具有1000多个数据元素的组件)
    • Type2AddComponent
      • BlockComponent
    • Type3AddComponent
      • BlockComponent

可以看出,BlockComponent正在所有三个TypeComponents中使用。三个不同BlockComponent中显示的TypeComponents数据相同(尽管标题 @Input)。 TypeComponent的第一次初始化加载很好,但是当它们之间切换时,加载时间超过3秒,我认为这是不合理的。有没有办法加快加载时间?

我知道下面分享了很多代码。如果我知道如何在 webpack 项目中创建一个Plunker。

共享data.service.ts

import { Injectable } from '@angular/core';
import { DataResolver } from '../../blocking/data/data.resolver';
import { Data } from 'si-data-model';
import { Observable } from 'rxjs/Observable';
import { Logger } from 'ngx-data-utils';

@Injectable()
export class DataService {

  data: Data[] = []; // shared data
  dataObs$: Observable<Data[]>;
  logger: Logger;
  completed = false; // used to signal whether the service has completed to components

  constructor(private resolver: DataResolver,
              logger: Logger) {
    this.logger = logger;
  }

  ngOnInit() {
    this.logger.debug('Data Service initialized.');
  }

  ngOnDestroy() {
    this.logger.debug('Data Service destroyed.');
  }

  load() {
    return this.resolver.resolve(); // retrieves the data elements from a web service
  }

  initData() {
    this.dataObs$ = this.load();
    this.dataObs$.subscribe((res: Data[]) => {
      this.data = res;
      this.completed = true;
    });
  }

}

add.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '../../shared/data/data.service';

@Component({
  selector: 'add',
  templateUrl: './add.component.html',
  styleUrls: ['./add.component.scss']
})
export class AddComponent implements OnInit, OnDestroy {

  radioUrl: string;

  constructor(private service: DataService) {
    console.log('Add component built');
  }

  ngOnInit() {
    this.service.initData();
    console.log('Add component initialized');
  }

  ngOnDestroy() {
    console.log('Add component destroyed');
  }

}

type1.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';

@Component({
  selector: 'type1',
  templateUrl: './type1.component.html',
  styleUrls: ['./type1.component.scss']
})
export class Type1Component implements OnInit, OnDestroy {

  title = 'Add Block Stuff';

  constructor() {
    console.log('Type1 component built');
  }

  ngOnInit() {
    console.log('Type1 component initialized');
  }

  ngOnDestroy() {
    console.log('Type1 component destroyed');
  }

  onType1Change($event: any) {
    console.log($event);
  }
}

block.component.ts

import { Component, OnDestroy, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { Logger } from 'ngx-data-utils';
import { Observable } from 'rxjs/Observable';
import { Data } from 'si-data-model';
import { DataService } from '../../shared/data/data.service';

@Component({
  selector: 'block',
  templateUrl: './block.component.html',
  styleUrls: ['./block.component.scss']
})

export class BlockComponent implements OnInit, OnDestroy {

  dataLoaded = false;
  labels = ['Label1', 'Label2', 'Label3', 'Label4',
    'Label5'];
  selected: any[] = [];
  data1: string;
  data2: string;
  data3: string;
  data4: string;
  data5: string;
  data6: string;
  datas: Data[] = [];
  @Output() change: EventEmitter<any> = new EventEmitter();
  @Input() title: string;
  @Input() data: Data[];

  // private criteriaCodes = [6, 2, 3, 11, 29, 25];

  constructor(private logger: Logger,
              private dataService: DataService) {
                // TODO
  }

  ngOnInit() {
    this.display();
    this.logger.debug('BlockComponent initialized.');
  }

  ngOnDestroy() {
    this.logger.debug('BlockComponent destroyed.');
  }

  initData () {
    this.dataService.data.forEach((dt: Data) => {
      this.datas.push(dt);
      this.dataLoaded = true;
    });
  }

  display() {
    if (this.dataService.completed) 
      this.initData();
  }

  propagateChange() {
    this.change.emit(this.selected); // doesn't do anything yet
  }

}

block.component.html

<div class="row" *ngIf="dataLoaded">
  <div class="row">
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL1' | translate}}</label>
      <select class="custom-select form-control" [(ngModel)]="data1" (change)="propagateChange()">
        <option *ngFor="let c of data[0].value">{{c.code}} - {{c.description}}</option>
      </select>
    </div>
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL2' | translate}}</label>
      <select class="custom-select form-control" [(ngModel)]="data2" (change)="propagateChange()">
        <option *ngFor="let mt of data[1].value">{{mt.code}} - {{mt.description}}</option>
      </select>
    </div>
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL3' | translate}}</label>
      <select class="custom-select form-control" [(ngModel)]="data3" (change)="propagateChange()">
        <option *ngFor="let pem of data[2].value">{{pem.code}} - {{pem.description}}</option>
      </select>
    </div>
  </div>
  <div class="row">
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL4' | translate}}</label>
      <select class="custom-select form-control" [(ngModel)]="data4" (change)="propagateChange()">
        <option *ngFor="let tt of data[3].value">{{tt.code}} - {{tt.description}}</option>
      </select>
    </div>
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL5' | translate}}</label>
      <select class="custom-select form-control" [(ngModel)]="data5" (change)="propagateChange()">
        <option *ngFor="let cl of data[4].value">{{cl.code}} - {{cl.description}}</option>
      </select>
    </div>
    <div class="col-md-4">
      <label>{{'DATA.BLOCK.LABEL6' | translate}}</label>
      <input type="text">
    </div>
  </div>
</div>

1 个答案:

答案 0 :(得分:0)

看起来add.component.ts每次重新初始化时都会重新获取数据?

你能做到这一点:

  initData() {
    if (!this.data) {
      this.dataObs$ = this.load();
      this.dataObs$.subscribe((res: Data[]) => {
        this.data = res;
        this.completed = true;
      });
    }
  }

然后,一旦数据被检索,它就不会重新加载数据。

关于子组件,它们中至少有一个是循环遍历 EVERY 元素并创建自己的数据数组副本?

  initData () {
    this.dataService.data.forEach((dt: Data) => {
      this.datas.push(dt);
      this.dataLoaded = true;
    });

相反,请尝试使用getter:

export class BlockComponent implements OnInit, OnDestroy {

  get datas(): Data[] {
      return this.dataService.data;
  }

  // ...

}