Данные исчезают после asyn c http-вызовов в Angular - PullRequest
0 голосов
/ 05 августа 2020

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

У меня есть три основных объекта: районы, здания и двери. Как вы можете догадаться, «двери» относятся к идентификатору здания, а идентификатор здания - к районам. Итак, чтобы получить данные и создать свои узлы дерева, мне нужно сделать несколько http-вызовов в циклах forEach, которые не являются асинхронными.

Я не буду делиться с вами всем, кроме минимизированной проблемы, чтобы я мог легко получить помощь :

Этот метод получает массив районов с сервера и помещает его в локальный массив:

async getDistricts(){
   this.districtDataService.getDistrictData().toPromise().then(async districts => {
     this.districts = await districts.results as District[];
   });

}

На моем ngOnInit:

ngOnInit() {
this.getDistricts().then(async () => {
  console.log(this.districts);
  for (const district of this.districts){
    console.log(district);
  }
})

Первый console.log (в NgOnInit) возвращает пустой массив, что довольно удивительно, потому что первый метод помещает данные в this.districts. и регистрация данных в первом методе сразу после того, как я их вставил, возвращает массив с моими данными. Я думаю, это как-то связано с используемым мной async / await. Может ли кто-нибудь помочь?

EDIT 1: Пытался использовать this.getDistricts (). Finally () вместо this.getDistricts (). Then (), но не сработало.

EDIT 2: console.log в getDistrict выполняется после того, что было перед моим l oop. Ожидаемое поведение было бы противоположным.

РЕШЕНО: размещение for l oop в блоке finally после того, как мой HTTP-вызов решает эту проблему. Итак, как говорится в ответе, я думаю, что перестал разрабатывать вызовы async / await. Исходя из этого, мне нужно переосмыслить свою работу. Всем спасибо!

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Ну, ты должен вернуть свой Promise из getDistricts. Кроме того, вы слишком сильно усложняете концепцию async/await. Я понимаю, что вы не хотите использовать Observables, но я бы посоветовал вам использовать их в любом случае.

С обещаниями и async/await, так что вы как бы видите, как их использовать:

async getDistricts(): Promise<District[]> {
  const { results } = await this.districtDataService.getDistrictData();
  
  return results;
}

async ngOnInit(): Promise<void> {
  this.districts = await this.getDistricts();

  for (const district of this.districts){
    console.log(district);
  }
}

С Observable это будет выглядеть так:

getDistricts(): Observable<District[]> {
  return this.districtDataService.getDistrictData().pipe(
    map(({ results }) => results as District[])
  );
}

ngOnInit(): void {
  this.getDistricts().subscribe((districts) => {
    this.districts = districts;
   
    for (const district of this.districts){
      console.log(district);
    } 
  });
}
0 голосов
/ 05 августа 2020

Просто для того, чтобы предоставить любому, кому нужно сделать несколько http-звонков в желаемом порядке. как упоминалось другими, я чрезмерно усложнил концепцию asyn c await. Хитрость заключалась в том, чтобы использовать наблюдаемые объекты, преобразовать их в обещания с помощью .toPromise (), использовать .then () для получения данных в мои переменные, а затем выполнить другие вызовы asyn c в блоке finally с использованием .finally (asyn c () => {...}).

вот как выглядит мой окончательный код:

async ngOnInit(): Promise<void> {
 await this.districtDataService.getDistrictData().toPromise().then(response => {
   this.districts = response.results as District[];
   console.log(this.districts);
 }).finally(async () => {
   for (const district of this.districts){
      await this.districtDataService.getBuildingsOfDistrict(district.id).toPromise().then(response => {
      this.buildings = response.results as Building[];
      console.log(this.buildings);
     }).finally(async ()=> {
        for(const building of this.buildings){
          await this.districtDataService.getDoorsOfBuilding(building.id).toPromise().then(response => {
            this.doors = response.results as Door[];
            console.log(this.doors);
          }).finally(async () => {
              for(const door of this.doors){
                  await this.doorNodes.push(new districtNodeImpl(false,null,null,door,null));
              }
          })
         await this.buildingNodes.push(new districtNodeImpl(false,null,building,null,this.doorNodes));
        }
     })
     await this.dataSource.push(new districtNodeImpl(false,district,null,null,this.buildingNodes));
     console.log(this.dataSource);
     this.buildingNodes = new Array();
     this.doorNodes = new Array();
   }
 })

Надеюсь, это поможет! хорошего дня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...