Недавно меня перевели в новый проект, который использует angular 6 в качестве внешнего интерфейса и spring для служб REST.
Проект находится в разработке уже 2 года, и я заметил, что почти все HTTP-запросы, сделанные с угловым HttpClient, затем направляются для получения фильтра из rxjs. Все REST API выдают только одно значение. Нет необходимости в ручной отмене и свойстве ленивости наблюдаемых.
Моя интуиция подсказывает, что использование toPromise() было бы лучшим способом кодирования.
о чем ты думаешь?
//customer-service.ts
constructor(private http: HttpClient) {
}
public getCustomers() {
return http.get('/customers');
}
//component.ts
public ngOnInit() {
this.customerService.getCustomers().pipe(take(1)).subscribe((customers) => {
//do some stuff
})
}
Мой предлагаемый подход:
//customer-service.ts
constructor(private http: HttpClient) {
}
public getCustomers() : Promise<Array<Customer>> {
return http.get('/customers').toPromise();
}
//component.ts
public ngOnInit() {
this.customerService.getCustomers().then((customers: Array<Customer>) => {
//do some stuff
})
}
Я думаю, что мой подход лучше, потому что он строго типизирован и чище.
А как насчет читабельности? Вы бы предпочли .pipe(take(1)).subscribe() или .then() ? А как насчет эффективности с точки зрения скорости вычислений?
Вы знаете, что тоже можете поставить pipe(take(1)) на службу? И вам даже не нужно take(1), потому что http observable завершается после отправки. Так что это просто subscribe против then. Но наблюдаемые гораздо чаще используются и более гибки.
Я понимаю. Еще один вопрос: если «http observable завершается после отправки», мне все еще нужно вызывать отмену подписки при подписке?
Нет, не знаешь. Вы можете сохранить подписку и проверить .isUnsubscribed самостоятельно.
Мне действительно больше нравится версия toPromise(), потому что вы можете просто дождаться ответа, что приведет к, на мой взгляд, более чистому коду! В большинстве случаев вам не нужно передавать данные по конвейеру. И мне кажется странным обрабатывать каждый http-запрос как поток данных, который я вручную преобразовываю, чтобы он вел себя как обычное обещание, используя две дополнительные функции фреймворка. В большинстве случаев мне просто нужен ответ из одного или нескольких источников, и я преобразовываю их все в промисы и использую await или await Promise.all([...]). После этого я могу использовать map/reduce/filter все встроенные функции ES6.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Как вы упомянули, строго типизированный, мы можем сделать то же самое в наблюдаемом подходе.
public getCustomers():Observable<Array<Customer>> {
return http.get<Array<Customer>>('/customers');
}
//component.ts
public ngOnInit() {
this.customerService.getCustomers()
.pipe(take(1))
.subscribe((customers: Array<Customer>) => {
//do some stuff
});
}
Старайтесь использовать Observable как можно чаще, как только вы ознакомитесь с ним, вы не пойдете на другие варианты. Итак, попробуйте!
Вам даже не нужно вводить возвращаемый функцией тип, он будет выведен из http.
Да, машинописный текст сделает вывод, но для удобочитаемости я писал вручную.
Вы можете просто навести указатель мыши на метод, и он уже явно введен <Array<Customer>>, поэтому я не вижу смысла вводить его дважды.
Переход от наблюдаемых к обещаниям — это шаг назад.
Это как перейти с Porsche 911 на Fiat multipla.
Так что нет, вам не следует использовать toPromise(), и нет, ваш способ не «лучше» (это эго, приятель!)
I think that my approach is better because it is strongly typed and it's cleaner.
Ввод ответа HTTP зависит не от предположений или наблюдаемых, а от самого разработчика. А чистота — это вопрос перспективы, лично я ненавижу видеть toPromise()s.
И главный недостаток вашего решения заключается в том, что после преобразования в обещание вы больше не можете ничего передавать, что делает ваши функции менее универсальными.
Но их код тоже не самый лучший. Обычно такое поведение используется для хранилищ и кешей, вы уверены, что ничего не пропустили?
В любом случае, если нет, и я полагаюсь только на предоставленный код, это будет правильный код:
public getCustomers() {
return http.get<Customer[]>('/customers');
}
....
public ngOnInit() {
this.customerService.getCustomers()
.subscribe((customers) => {...})
}
Такой глупый уничижительный комментарий. Лучшая аналогия заключается в том, что если вам нужен только Fiat, но вы продолжаете ездить на Porsche, его обслуживание обойдется вам в 10 раз дороже, если вы не используете все функции Porsche. @ Джордж, рассмотрите возможность удаления принятого ответа. Превращение наблюдаемого объекта, который запускает только одно событие, в обещание, упрощает отслеживание вашего кода и работу с ним, вам не нужно беспокоиться о том, что обратный вызов вызывается несколько раз, и вам не нужно отписываться.
На самом деле принятый ответ вводит в заблуждение, говоря, что преобразование наблюдаемого в обещание похоже на шаг назад. Скорее это о том, каковы ваши потребности. как указано в Угловая документация:
Observables differentiate between chaining and subscription. Promises only have .then() clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed.
И разница между toPromise() и take(1) (или для краткого использования оператора first()) заключается в том, что take(1) завершается после того, как 1-е испущенное значение, в то время как toPromise ожидает последнего испущенного значения (ожидает, пока наблюдаемое значение Complete затем разрешает последнее сгенерированное значение).
Еще одно различие между наблюдаемыми и промисами, которое может вас заинтересовать, заключается в том, что подписки на Observable можно отменить, а промисы — нет. В качестве конкретного примера, скажем, ваш API /customers требует времени, но вам больше не нужны результаты, и вы переходите на другую страницу, отказ от подписки отменяет HTTP-запрос.
Почему? Потому что позже будет проще:
С другой стороны, вы правы, ваш код более читаем, чем код других, но вы также можете изменить Observable так, чтобы он был таким же хорошим, как ваш (просто добавьте к нему строгую типизацию), и он по-прежнему сохраняет функциональность и согласованность Наблюдаемые.
Оба строго типизированы, а остальная часть Angular использует Rx, так что нет.