Подтвердить что ты не робот

Как я могу вернуть ответ от Observable/http/async на угловой?

У меня есть служба, которая возвращает наблюдаемый, который выполняет HTTP-запрос на мой сервер и получает данные. Я хочу использовать эти данные, но всегда получаю undefined. В чем проблема?

Сервис

@Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}

компонент:

@Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}
4b9b3361

Ответ 1

Причина:

Причина, по которой он undefined заключается в том, что вы выполняете асинхронную операцию. Это означает, что для завершения метода getEventList потребуется некоторое время (в зависимости от скорости вашей сети).

Итак, давайте посмотрим на http-вызов.

this.es.getEventList()

После того, как вы на самом деле сделаете ( "огонь" ) свой HTTP-запрос с помощью subscribe, вы будете ожидания для ответа. Во время ожидания javascript выполнит строки под этим кодом, и если он встретит синхронные назначения/операции, он немедленно выполнит их.

Итак, после подписки на getEventList() и ожидания ответа

console.log(this.myEvents);

Строка

будет выполнена немедленно. И значение этого параметра равно undefined до того, как ответ поступит с сервера (или на то, что вы его инициализировали в первую очередь).

Это похоже на выполнение:

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}


Решение:

Итак, как мы можем преодолеть эту проблему? Мы будем использовать функцию обратного вызова, которая является методом subscribe. Поскольку, когда данные поступают с сервера, он будет находиться внутри subscribe с ответом.

Итак, измените код на:

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });

напечатает ответ.. через некоторое время.


Что вы должны сделать:

В вашем ответе может быть много чего другого, кроме как его регистрация; вы должны делать все эти операции внутри обратного вызова (внутри функции subscribe), когда данные поступают.

Еще одна вещь, которая стоит упомянуть, заключается в том, что если вы пришли из фона Promise, обратный вызов then соответствует subscribe с наблюдаемыми.


Что вы не должны делать:

Не следует пытаться изменить операцию async на синхронизацию (не то, что вы можете). Одной из причин, по которым мы имеем асинхронные операции, является то, что пользователь не должен ждать завершения операции, пока они могут делать другие вещи за этот период времени. Предположим, что одна из ваших асинхронных операций занимает 3 минуты, если у нас не было асинхронных операций, интерфейс застыл в течение 3 минут.


Рекомендуемое чтение:

Оригинальный кредит на этот ответ: Как вернуть ответ от асинхронного вызова?

Но с выпуском angular2 мы познакомились с typescript и наблюдаемыми, поэтому в этом ответе мы надеемся осветить основы обработки асинхронного запроса с помощью наблюдаемых.

Ответ 2

Создание http-вызова в angular/javascript - асинхронная операция. Поэтому, когда вы делаете http-вызов, он назначит новый поток для завершения этого вызова и начнет выполнение следующей строки с помощью другого потока. Вот почему вы получаете значение undefined. поэтому сделайте ниже изменение, чтобы решить эту проблему.

this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });

Ответ 4

Проблема в том, что вы инициализируете this.myEvents в subscribe() который является асинхронным блоком, в то время как вы выполняете console.log() только из блока subscribe(). Поэтому console.log() this.myEvents до того, как this.myEvents будет инициализирован.

Пожалуйста, переместите свой код console.log(), а также в subscribe(), и все готово.

ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents);
        });
  }

Ответ 5

Также убедитесь, что вы сопоставили свой ответ с выводом json. В противном случае он вернет простой текст. Вы делаете это так:

getEventList(): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });

return this.http.get("http://localhost:9999/events/get", options)
            .map((res)=>{ return res.json();}) <!-- add call to json here
            .catch((err)=>{return err;})
}

Ответ 6

Наблюдаемые ленивы, поэтому вам нужно подписаться, чтобы получить ценность. Вы подписали его правильно в своем коде, но одновременно регистрировали вывод вне блока "подписаться". Вот почему он "неопределен".

ngOnInit() {
  this.es.getEventList()
    .subscribe((response) => {
        this.myEvents = response;
    });

  console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}

Поэтому, если вы запишете его в блоке подписки, он будет корректно регистрировать ответ.

ngOnInit(){
  this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //Inside the subscribe block 'http response'
    });
}

Ответ 7

Результат не определен, потому что угловой процесс асинхронен. Вы можете попробовать, как показано ниже:

async ngOnInit(){
    const res = await this.es.getEventList();
    console.log(JSON.stringify(res));
}

Ответ 8

Вы можете просто попробовать этот метод -

let headers = new Headers({'Accept': 'application/json'});
let options = new RequestOptions({headers: headers});

return this.http
    .get(this.yourSearchUrlHere, options) // the URL which you have defined
    .map((res) => {
        res.json(); // using return res.json() will throw error
    }
    .catch(err) => {
        console.error('error');
    }