Дочерний компонент в Angular, использующий привязку ввода, работает медленно при использовании службы геокодирования Карт Google - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть MEAN-приложение, использующее Angular и google.maps.Geocoder () из API Карт Google.Он показывает карту и может искать / визуализировать адреса.Я делаю это в компоненте «карта», и все работает.У меня есть дочерний компонент формы, который показывает результаты.Однако требуется несколько секунд (иногда до 20), чтобы компонент формы обнаружил изменения и отобразил их.Как так?

Возможная причина:

Возможно, основной поток JS занят моим запросом, блокируя обновление дочернего компонента.В сетевом журнале браузера я вижу файл с именем «websocket» (я думаю, что аналогичный создается при поиске) с «Ожиданием» времени и предупреждением «запрос еще не завершен».Интересно, почему это блокирует Angular (в частности, обновление дочернего компонента) и как этого избежать.

Подробнее:

Родитель и ребенок общаются через привязку ввода, и я также использую ngOnChanges для обмена данными.Для простоты у меня есть тест, в котором я просто перехожу из карты (родительский компонент) в форму (дочерний компонент) логического значения "formBoolean".Логическое значение отображается в форме после поиска по геокодированию, но, как уже было сказано, до того, как это произойдет, потребуется несколько секунд.

Примечание: когда я удаляю геокодирование из обратного вызова findLocation (), дочерний компонент быстро показывает изменения в логическом значении.Вот почему я думаю, что геокодирование "делает угол медленным"


Мой упрощенный код, показанный ниже, должен проиллюстрировать проблему.

index.html указывает на maps.googleapis.com с моим ключом API (не показан).

map.component.ts (родительский компонент):

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


@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
})

export class MapComponent implements OnInit {
  ngOnInit() {
    //Here I omit mapProp in the call to Map() above
    this.map = new google.maps.Map(this.gmapElement.nativeElement); 
  }

  @ViewChild('gmap') gmapElement: any;
  map: google.maps.Map;
  geocoder: any;
  formChanged: boolean = false;

  findLocation() {  
    if (!this.geocoder) this.geocoder = new google.maps.Geocoder();
    this.geocoder.geocode({
      'address': '1116 S Long Beach Blvd, Compton, CA 90221, USA',
      'componentRestrictions': {country: 'US'} //I use country restriction
      }, (results,  status) => {
        //I omit how I manipulate the results object, place a marker on the map, and pass data to child. 
        //The marker on the map appears immediately. I can console.log results
        //For this example I just pass to the form component the followin boolean:
        this.formChanged = !this.formChanged;
      }

}

map.component.html (родительский компонент):

<!--For simplicity i just show the button and the binding to the child component--> 
<button type="submit" class="btn btn-primary" (click)="findLocation()">Search</button>

<app-form [formChanged]="formChanged" [formResult]="formResult"></app-form>

form.component.ts (дочерний компонент):

import { Component, Input } from '@angular/core';
import { OnChanges, SimpleChanges, SimpleChange } from '@angular/core';

@Component({
  selector: 'app-form',
  templateUrl: '{{formChanged}}',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit, OnChanges {
  @Input('formResult') formResult: Store;
  @Input('formChanged') formChanged: boolean;

  constructor(private storeService: StoreService){}

  ngOnChanges(changes: SimpleChanges){
    console.log('form - ngOnChanges',changes)
  }
}

Как уже говорилось, геокодирование работает, но может пройти 20 секунд, прежде чем дочерний компонент "формы" будет обновлен, и я вижу изменения в консоли

1 Ответ

0 голосов
/ 26 ноября 2018

Вы можете переместить тяжелую операцию, которая может заблокировать основной поток 'Найти местоположение', в асинхронный вызов, используя обещания.

findLocation() {  
    if (!this.geocoder) this.geocoder = new google.maps.Geocoder();
    return new Promise((resolve, reject)=>{
       this.geocoder.geocode({
         'address': '1116 S Long Beach Blvd, Compton, CA 90221, USA',
         'componentRestrictions': {country: 'US'} //I use country restriction
         }, (results,  status) => {
            //I omit how I manipulate and pass data to child. For this exampl
            just pass the followin boolean:
            this.formChanged = !this.formChanged;
            resolve(true);
          });
     });

}
...