Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 19.03.2019, 13:12
Интересующийся
Отправить личное сообщение для kotelok Посмотреть профиль Найти все сообщения от kotelok
 
Регистрация: 27.08.2018
Сообщений: 22

Дождаться завершения 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"]);
Ответить с цитированием
  #2 (permalink)  
Старый 19.03.2019, 13:22
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 2,952

Тут, по-моему, неплохим решением было бы возвращать Promise.

methodName(){
    if( hasCachedResponse )
        return Promise.resolve(cachedResponse);

    return new Promise(resolve=>{
        makeRequest().subscribe(response=>{
            cacheResponse(response);

            resolve(response);
        });
    });
}
Ответить с цитированием
  #3 (permalink)  
Старый 19.03.2019, 14:07
Интересующийся
Отправить личное сообщение для kotelok Посмотреть профиль Найти все сообщения от kotelok
 
Регистрация: 27.08.2018
Сообщений: 22

Получилась такая вот странная конструкция для подгрузки конфига, если его нет в кэше:
----
    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?
Ответить с цитированием
  #4 (permalink)  
Старый 19.03.2019, 14:08
Аватар для destus
Профессор
Отправить личное сообщение для destus Посмотреть профиль Найти все сообщения от destus
 
Регистрация: 18.05.2011
Сообщений: 1,176

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 классе.
Ответить с цитированием
  #5 (permalink)  
Старый 19.03.2019, 14:12
Интересующийся
Отправить личное сообщение для kotelok Посмотреть профиль Найти все сообщения от kotelok
 
Регистрация: 27.08.2018
Сообщений: 22

Сообщение от destus Посмотреть сообщение
kotelok,
Ну раз это конфиг, и запрашивается с сервера он видимо 1 раз, то можно использовать APP_INITIALIZER
Это понятно. Просто взял наиболее простой пример. Но в общем случае меня интересовало то, что в следующем посте обозначил - как не плодя вложенность реализовывать в рамках одного метода последовательное выполнение http-запросов. Т.е. когда следующий вызов зависит от результата выполнение предыдущего запроса.
Ответить с цитированием
  #6 (permalink)  
Старый 19.03.2019, 14:17
Аватар для destus
Профессор
Отправить личное сообщение для destus Посмотреть профиль Найти все сообщения от destus
 
Регистрация: 18.05.2011
Сообщений: 1,176

Цитата:
Но в общем случае меня интересовало то, что в следующем посте обозначил - как не плодя вложенность реализовывать в рамках одного метода последовательное выполнение http-запросов. Т.е. когда следующий вызов зависит от результата выполнение предыдущего запроса.
mergeMap, switchMap в помощь
Ответить с цитированием
  #7 (permalink)  
Старый 19.03.2019, 15:32
Интересующийся
Отправить личное сообщение для kotelok Посмотреть профиль Найти все сообщения от kotelok
 
Регистрация: 27.08.2018
Сообщений: 22

В общем, попробовал по аналогии с 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);

Последний раз редактировалось kotelok, 19.03.2019 в 15:37.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Дождаться завершения функции и продолжить выполнение кода XRASER Events/DOM/Window 4 10.04.2014 16:39
почему селект вдруг перестал работать в эксплорере и гуглхроме? Краса (X)HTML/CSS 44 04.05.2013 19:18
Дождаться выполнение запроса. psyhonut jQuery 6 12.09.2010 12:25