Дождаться завершения HTTP-запроса, но не всегда
Подскажите, как правильно реализовать следующую логику (см код):
1. Если есть закэшированный конфиг, то пропустить его запрос с сервера и сразу перейти к выполнению последующего кода (последняя строка). 2. Если НЕТ закэшированного конфига, то запросить его с сервера, дождаться (!) результата и, если ок, то сохранить в кэш и после этого перейти к последующему коду (последняя строка). Если ошибка - завершить выполнение. В том виде, что сейчас написано работает некорректно, т.е. 'console.info' начинает выполняться ещё до получения ответа по 'httpClient.get'. При этом помещать 'console.info' внутерь подписки тоже нельзя, т.к. в этом случае он не выполнится, если данные изначально есть в кэше. Дублировать вызов тоже как-то неправильно с точки зрения организации кода. Собственно, какой синтаксис позволит запустить 'httpClient.get' синхронно, т.е. чтобы до его полного завершения не происходило выполнения последующего кода этого метода?
----
if (this.appConfig.authServerConfig == null) {
this.httpClient.get("{auth}/.well-known/openid-configuration").subscribe((response:string) => {
this.appConfig.authServerConfig = response;
},
(httpError:HttpErrorResponse) => {
console.error("error: get auth server config");
});
}
console.info(this.appConfig.authServerConfig["token_endpoint"]);
|
Тут, по-моему, неплохим решением было бы возвращать Promise.
methodName(){
if( hasCachedResponse )
return Promise.resolve(cachedResponse);
return new Promise(resolve=>{
makeRequest().subscribe(response=>{
cacheResponse(response);
resolve(response);
});
});
}
|
Получилась такая вот странная конструкция для подгрузки конфига, если его нет в кэше:
----
private getAuthConfig(): Observable<boolean> {
if (this.appConfig.authServerConfig != null) {
return Observable.of(true);
}
return this.httpClient.get("{auth}/.well-known/openid-configuration").flatMap((response: string) => {
this.appConfig.authServerConfig = response;
return Observable.of(true);
}).catch(error => {
return Observable.of(false);
});
}
И такой код, для его вызова:
----
this.getAuthConfig().subscribe((config) => {
if (config != true) {
console.error("error: auth server config");
return;
}
console.info(this.appConfig.authServerConfig["token_endpoint"]);
});
Но как-то очень уж громоздко выглядит для простой логики. И ещё возникает проблема, когда требуется несколько http-запросов последовательно выполнить в рамках одного блока логики, т.е.: 1. Что-то забрать с сервера по http-get. 2. После п.1. отправить первый http-post. 3. После п.2. что-то сделать с полученным данными, выполнить следующий http-post. 4. После п.3 произвести обработку данных для отображения пользователю. У меня, почему-то, каждый раз получаются многоуровневые вложенные конструкции, которые сложно читать. Т.е. по логике кода - одноуровневые последовательные запросы, а реализация - многовложенная. Можно это как-то обойти или это специфика JS? |
kotelok,
Ну раз это конфиг, и запрашивается с сервера он видимо 1 раз, то можно использовать APP_INITIALIZER хук https://blog.zverit.com/frontend/201...ervice-method/ Кстати вместо этого
return new Promise(resolve=>{
makeRequest().subscribe(response=>{
cacheResponse(response);
resolve(response);
});
});
можно использовать toPromise() метод, который определен на Observable классе. |
Цитата:
|
Цитата:
|
В общем, попробовал по аналогии с C#. Похоже, в TS тоже есть какая-то реализация 'await' и, судя по поведению, работает она похожим образом. Т.е. пока await-блок не завершится, следующий за ним оператор ожидает своей очереди. Последовательные (зависимые) http-вызовы при таком подходе записываются намного нагляднее. При этом сам метод возвращает управление после первого же 'await', а весь остальной хвостик продолжает выполнение параллельно.
----
//
await (async () => {
if (this.appConfig.authServerConfig != null) {
return null;
}
return this.httpClient.get("{auth}/.well-known/openid-configuration").toPromise().then((response:string) => {
this.appConfig.authServerConfig = response;
}, (error:HttpErrorResponse) => {
console.info(error);
});
})();
//
if (this.appConfig.authServerConfig == null) {
return;
}
//
console.info(this.appConfig.authServerConfig);
|
| Часовой пояс GMT +3, время: 09:46. |