Как правильно использовать наблюдаемые, async/await и подписаться в angular

У меня есть файл свойств json в папке assets/constants/props.json. В файле json у меня есть одно имя ключа someValue и его значение abc.

JSON-файл выглядит так:

У меня есть служебный файл constants.service.ts и в нем 2 метода:

  public getJson(url : string) : Observable<any> {
    return this.http.get(url);
  }

  public someValue() : string {
    return this.getJson("assets/constants/props.json").subscribe(async (data: any) => {
      return await data.someValue;
    });
  }

А также в одном из своих компонентов я использую это значение:

  private someValue! : string;

  ngOnInit() {
    this.someValue = this.server.someValue();
  }

Таким образом я получаю: Type 'Subscription' is not assignable to type 'string'. ошибка.

Я пробовал много способов, и ни один из них не работал:

  1. метод make someValue() возвращает Promise<string>

  2. сделать ngOnInit() асинхронный метод и использовать await в нем

  3. используя unsubsribe, toPromise(), toString()...

И многое другое...

Каждое решение выдавало мне другое сообщение об ошибке или неправильное значение [object object] вместо «abc».

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

Мой вопрос в том, как правильно использовать observables, async, await, subscribe

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
0
122
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете напрямую преобразовать Observable<string> или Promise<string> в string, потому что это не имеет семантического смысла.

И Observable, и Promises представляют значения, которые пока недоступны, но могут быть предоставлены в какой-то момент в будущем. Поскольку все API-интерфейсы ввода-вывода JavaScript, о которых я знаю, спроектированы неблокирующими, вы не можете позволить своему процессу бездействовать, ждать и ничего не делать (т. е. блокировать), пока не завершится операция ввода-вывода.

Вместо этого вы регистрируете функцию обратного вызова, которая будет вызываться в более поздний момент времени, когда значение будет доступно. Вот для чего нужны subscribe в RxJS или then в Promises.

Ключевые слова async и await — это просто синтаксический сахар для создания промисов и регистрации на них обратных вызовов соответственно. Под капотом async он просто преобразует код, который следует за ним, в функцию обратного вызова и регистрирует его в промисе. Так что в вашем примере он вообще ничего полезного не делает.

Есть несколько способов получить значение из Observable.

Вот самое простое:

ngOnOnit() {
  this.server.someValue().subscribe(value => this.someValue = value);
}

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

Есть лучший способ: просто позвольте Angular разобраться с этим, используя AsyncPipe. Просто отправьте Observable прямо в шаблон и дайте Angular подписаться на него:

someValue$: Observable<string>; // The "$" sign is just naming convention to tell Observables and plain values apart

ngOnInit() {
  this.someValue$ = this.server.someValue();
}
<p>Your value: {{someValue$ | async}}</p>

В качестве примечания: мы надеемся, что все это станет намного проще с Angular 16, когда он получит поддержку Signals.

но если я использую вашу идею this.server.someValue().subscribe(value => this.someValue = value); и пишу alert(this.someValue) после предыдущей строки, я получаю undefined, если я не жду несколько миллисекунд, и тогда это сработает. Как я могу дождаться фактической загрузки значения, а затем сделать предупреждение. Почему await не работает?

php123 14.04.2023 14:34

await работает над Promise, а Observable не является Promise. Вы можете преобразовать Observable в Promise, например. используя lastValueFrom, а затем ждите его.

chris 15.04.2023 10:36

И, конечно, значение недоступно сразу, потому что вы имеете дело с асинхронным вводом-выводом. Это то, что я пытался объяснить все это время, я, честно говоря, не знаю, как сделать это яснее.

chris 15.04.2023 10:38

Также я по-прежнему рекомендую AsyncPipe вместо lastValueFrom + await.

chris 15.04.2023 10:40

Другие вопросы по теме