Angular 4. Откликается серия HTTP-запросов

Когда я пытаюсь сделать несколько HTTP-запросов через http-сервис в Angular 4, предыдущий запрос отменяется в Chrome (но они доходят до сервера). Пример:

const obs1 = this.http.get(`${API_URL}/transitions`);
const obs2 = this.http.get(`${API_URL}/states`);
obs1.subscribe();  
obs2.subscribe(); // this will cancel obs1 http request

Но если я заменил .subscribe() на .publish().connect(), как указано выше, он будет работать правильно (не отменяется)

const obs1 = this.http.get(`${API_URL}/transitions`);
const obs2 = this.http.get(`${API_URL}/states`);
obs1.publish().connect();
obs2.publish().connect();

Или, если я объединить два Observables в один, а затем подписаться, как указано выше, он будет работать правильно.

const obs1 = this.http.get(`${API_URL}/transitions`);
const obs2 = this.http.get(`${API_URL}/states`);
Observable.merge(obs1, obs2).subscribe()

Почему мне приходится сталкиваться с таким поведением? Мне нужно понять, а не обходить. Как я могу сделать серию запросов без слияния, форсирования и т.д.?

Ответ 1

Я нашел потенциальную причину такого поведения.

Благодаря https://github.com/ghetolay и https://github.com/dklmuc

Мы обнаружили, что angular отменит очень быстрые HTTP-запросы, которые без обратного вызова. Итак, вы должны пройти onNext в подписке

Из https://github.com/ghetolay:

ОК это состояние гонки Я думаю

он всегда будет вызывать xhr.abort() при разрыве

если соединение по-прежнему считается открытым браузером, оно закроет его, иначе, возможно, ничего не сделает

поэтому, когда вы очень быстро обрабатываете ответ (например, обратный вызов действительно очень быстрый), он может прервать соединение, которое все еще считается открытым

Это работает правильно:

for (let i = 1; i < 50; i++) {
    http.get(`https://swapi.co/api/people/${i}`).subscribe((result) => {
        console.log(i, result);
    });
}

Ответ 2

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

Я столкнулся с аналогичной проблемой, используя модуль ngrx/effects. Обработчик действий отправил запросы на услугу с помощью оператора карты переключения ngrx. Все, кроме последнего запроса, будут отменены. Исправлена проблема с изменением его для объединения карты. Ниже приведен код

@Effect()
    loadSomeData$: Observable<Action> = this.actions$
            .ofType(SomeActions.Load_Data)
            .mergeMap((id) =>
                    this.someService.getSomething(id)
                            .map((someEntity) => new SomeActions.LoadDataSuccess(someEntity)
                            ).catch((x, y) => {
                                    console.error('Error occured');
                                    return Observable.of(new SomeActions.LoadDataFailed(id));
                            }
                            ));

Воспроизведение соответствующей части ngrx здесь.

https://www.learnrxjs.io/operators/transformation/switchmap.html

Основное различие между switchMap и другими операторами сплющивания - эффект отмены. При каждом излучении предыдущий внутренний наблюдаемый (результат функции, который вы поставили) отменяется, и подписывается новый наблюдаемый. Вы можете запомнить это с помощью переключателя фразы на новое наблюдаемое.

Ответ 3

Для меня проблема была из-за пустой наблюдаемой. Я использовал Observable.forkJoin в списке наблюдаемых.

РЕШЕНИЕ: Мне нужно было дать мне Observable.of() значение: Observable.of(null)

Ответ 4

Я сталкиваюсь с той же проблемой с mergeMap. Мой звонок сразу же отменяется после его запуска. Это происходит только после первого вызова проверки подлинности. Если сначала выполняется вызов Nodes, он будет выполнен правильно.

fetchNodes = (action$: ActionsObservable<any>) => {
    const fetchNodesFulfilled = payload => ({ type: NodesActions.FETCH_NODES_SUCCESS, payload });
    return action$.pipe(
        ofType(NodesActions.FETCH_NODES),
        mergeMap(
            ({payload}) => {
                let headers = new HttpHeaders({
                    'Authorization': 'basic ' + this.auth.user.getValue().token,
                });
                return this.http.get<Nodes>('${ENV.apiUrl}/nodes', { headers: headers })
                    .map(payload => fetchNodesFulfilled(payload.nodes[0]))
                    .catch((error) => {
                        return Observable.of({
                            type: NodesActions.FETCH_NODES_FAILED
                        })
                    });
            })
        ).catch((error) => {
            return Observable.of({
            type: NodesActions.FETCH_NODES_FAILED
        }) 
    })
}