Дождаться завершения 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, время: 08:02. |