Angular 2, почему мои 4 вызова API не ждут завершения предыдущего вызова перед выполнением?

У меня есть _1 _ / _ 2_, который должен выполнить 4 отдельных вызова API, чтобы «сохранить». На самом деле, только одна из этих транзакций должна ждать остальных 3, но я все равно хотел связать все 4 из них на всякий случай.

Вот как я его настраиваю:

save() {
    this.save1(saveObject1)
        .subscribe(response => {
            if (response === 0) {
                this.processErrorResult('save1');
            }

            this.save2(saveObject2)
                .subscribe(response2 => {
                    if (response2 === 0) {
                        this.processErrorResult('save1');
                    }

                    this.save3(saveObject3)
                        .subscribe(response3 => {
                            if (response3 === 0) {
                                this.processErrorResult('save1');
                            }

                            if (this.noErrorsInFirst3Saves()) {
                                this.save4(saveObject4)
                                    .subscribe(response4 => {
                                        if (response4 === 0) {
                                            this.processErrorResult('save1');
                                        }

                                        if (!this.hasErrors()) {
                                            this.router.navigate(['confirmation']);
                                        }
                                    });
                            }
                        });
                });
        });
}

private save1(saveObject: any): Observable<int> {
    this.api.save1(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save2(saveObject: any): Observable<int> {
    this.api.save2(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save3(saveObject: any): Observable<int> {
    this.api.save3(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save4(saveObject: any): Observable<int> {
    this.api.save4(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

Внутри каждой из этих save{number} функций у меня есть сообщения журнала, поэтому я точно знаю порядок, в котором эти функции выполняются (и ответы возвращаются).

Когда я нажимаю кнопку «Сохранить», он [почти] немедленно перенаправляется на мою страницу подтверждения, после чего я могу сидеть и смотреть в окно консоли в инструментах Chrome dev и видеть, как начинают поступать ответы на вызовы API.

Почему эта установка не принимает явное связывание этих транзакций? Я знаю, что в Angular 1 это было очень легко сделать с promise и с .then(response => {});.

Единственное, что я могу придумать, отличается, это для КАЖДОГО вызова API, будь то _8 _ / _ 9 _ / _ 10 _ / _ 11_, он всегда показывает 2 вызова на сетевой панели инструментов chrome dev. Первый вызов имеет RequestMethod, установленный на Options, а последующий вызов - это соответствующий _14 _ / _ 15 _ / _ 16 _ / _ 17_ с соответствующим установленным RequestMethod.

Я не помню, чтобы когда-либо видел эти (дублированные вызовы) ни в одном из моих недавних приложений, над которыми я работал (возможно, я просто никогда не обращал на это внимания), так что, возможно, это просто стандартная операционная процедура для вызовов API.

Есть идеи здесь?

Изменить: в ответ на предложенный ниже ответ Гарри

Я пытаюсь реализовать ваш ответ, но все еще немного запутался в том, как реализовать, вот более подробный взгляд на мою настройку:

private save1(saveObject: any): Observable<number> {
    if (saveObject.hasChanges()) {
        return this.api.save1(saveObject)
            .map(successful => {
                return this.parseSaveResponse(successful, saveObject, true); // true indicates a successful API response
            })
            .catch(failed => {
                return this.parseSaveResponse(successful, saveObject, false); // false indicates a successful API response
            });
    } else {
        return Observable.of(-1); // no changes necessary, return immediately
    }
}

private parseSaveResponse(response: any, saveObject: any, transactionSuccessful: boolean) {
    this.logService.logTransaction({transactionType}, saveObject, response, transactionSuccessful);

    if (!transactionSuccessful) {
        // add to error list object to be displayed on the form
        return 0;
    }

    return 1;
}

Когда он дошел до этого момента, он выдает мне ошибку в строке .catch({});, говорящую:

Аргумент типа '(ошибка: любая) => 0 | 1 'не может быть назначен параметру типа' (err: any, catch: Observable ‹0 | 1>) => ObservableInput‹ {}> '. Введите '0 | 1 'не может быть назначен типу' ObservableInput ‹{}> '. Тип '0' нельзя присвоить типу 'ObservableInput ‹{}>'.)


person ganders    schedule 08.09.2017    source источник
comment
посмотрите на оператор преобразования switchmap в rxjs, чтобы связать свои вызовы. Он может принимать Observable в качестве входных данных, и вы можете использовать его для вызова другого API. Если вы хотите подождать, вы можете изучить метод Observable.forkJoin   -  person DOMZE    schedule 08.09.2017


Ответы (2)


Есть довольно много проблем с вашим кодом, которые могут способствовать. Во-первых, ваши методы save1 / save2 / save3 должны просто возвращать наблюдаемое из вашего API, на которое вы сможете подписаться.

Во-вторых, вы используете тип int, которого нет в Typescript. Используйте число.

private save1(saveObject: any): Observable<number> {
  return this.api.save1(saveObject);
}
// or
private save1(saveObject: any): Observable<number> {
  return this.api.save1(saveObject).map(response => 1).catch(response => 0)
}

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

Наконец, вам следует избегать подписки на наблюдаемое изнутри наблюдаемого. Вы можете связать наблюдаемые вместе с помощью оператора flatMap. Это преобразует элементы, излучаемые Observable, в Observable, а затем сглаживает выбросы от них в один Observable.

save() {
  this.save1(saveObject1)
    .flatMap(response1 => this.save2(saveObject2))
    .flatMap(response2 => {
      if (response2 === 0) {
        // handle error
      }
      return this.save3(saveObject3);
    })
    .flatMap(() => this.save4(saveObject4))
    .subscribe(response4 => {
      // do redirect
    });
  }

http://reactivex.io/documentation/operators/flatmap.html

person Harry    schedule 08.09.2017
comment
извините, они уже возвращают Observable ‹number›, это была просто запись псевдокода, и я забыл, что я был в мире машинописных текстов, а не C #. Я прочитаю оставшуюся часть вашего ответа ... - person ganders; 08.09.2017
comment
Я считаю, что у меня это работает ... как только я подтвердю еще несколько тестов, я обновлю свой вопрос, чтобы получить рабочую версию, и я награжу вас баллами за ответы. Спасибо [я думаю] ... - person ganders; 08.09.2017

Я думаю, вам нужно «вернуть» свои наблюдаемые. Бывший:

Измените это:

this.api.save1(saveObject)

To:

return this.api.save1(saveObject)
person vidalsasoon    schedule 08.09.2017
comment
даже если у каждого из этих this.api.save1() вызовов есть .subscribe, и что они делают return Observable.of({number});? - person ganders; 08.09.2017
comment
@ganders да. вам нужны оба возврата - person vidalsasoon; 08.09.2017
comment
как только я добавляю return, в котором вы указали, vscode выдает красную строку ошибки под всем блоком, говоря: type subscription is not assignable to type Observable<number> - person ganders; 08.09.2017
comment
вернуть 1 вместо Observable.of (1)? не уверен отсюда - person vidalsasoon; 08.09.2017
comment
Пробовал, ошибку не изменил. Если я удалю : Observable<int> { из этой строки: private save1(saveObject: any): Observable<int> {, тогда он сбрасывает ошибку там, но затем показывает ошибку в функции сохранения, говорящую Property 'subscribe' does not exist on type 'Subscription | Observable<number>' - person ganders; 08.09.2017