Тип возврата Angular Typescript для вложенных подписок - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть функция, которая вызывает несколько методов обслуживания.Эта функция находится в сервисном объекте, который мне нужно вызвать из app.component.ts, оттуда мне нужно подождать, пока эта функция будет завершена, чтобы выполнить больше кода.У меня вопрос, как я могу изменить тип возвращаемого значения, чтобы я мог подписаться на него с app.component.ts Мой код такой, как показано ниже.

public registerAndGetToken() {

   this.initializeRegistration().subscribe((match)=> {

   // if initialization is success then invoke callback function
   // initializationCallback() will return a boolean (synchronous function)

   const callbackResult = this.initializationCallback(match);

   if(callbackResult) {

       this.renewToken().subscribe((tokenResult)=> {

       //renewTokenCallback is a synchronous function
       this.renewTokenCallback();
       //what to return from here??
       }, 
      (tokenError) => {
      //what to return from here?? 
      });
   }
   else {
    // what to return from here??
   }
 },
(error) => {
 // what to return from here??
});

Я пытался добавить «возврат» на this.initializeRegistration(), затем return Observable.of(true); и измените сигнатуру метода на public registerAndGetToken(): Observable<boolean>.Но это не нравится.Говорит,

Тип «Подписка» нельзя назначить типу «Наблюдаемый».
Свойство «_isScalar» отсутствует в типе «Подписка».[2322]

1 Ответ

0 голосов
/ 30 ноября 2018

У вас слишком много подписчиков.:)

Однажды я услышал несколько хороших советов по поводу Observables - «с подозрением относиться к подписке внутри подписки».Это очень хороший совет, потому что, вероятно, это означает, что я неправильно подхожу к проблеме, если делаю это.Как общее практическое правило, я также склонен не подписываться внутри сервиса, а оставить его для компонента (или, что еще лучше, только для шаблона компонента).В противном случае существует слишком много возможностей для утечек памяти, пытаясь удостовериться, что я отписал их всех.

В вашем случае я рад, что вы указали rxjs 5.5, потому что именно тогда был введен оператор .pipe, и это сделает вашкод значительно проще писать я думаю.Я многого не знаю о вашем коде, поэтому я предлагаю следующее не в качестве решения «вырезать и вставить», а в качестве примера того, как его реорганизовать, чтобы убрать все подписки из вашего сервиса и в конечном итоге вернутьнаблюдаемый, на который можно подписаться в вашем компоненте, как вы указали в своем вопросе.

Вот код, о котором вы можете подумать:

public registerAndGetToken() {
    return this.initializeRegistration().pipe( // <-- return an Observable
        catchError((error) => {
            // handle case when initializeRegistration gives back an error,
            // for example:
            return throwError(`initializeRegistration() threw error: ${error.message}`);
            // This assumes the error will be bubbled up to the component
        }),
        mergeMap((match) => {
            const callbackResult = this.initializationCallback(match);
            if(callbackResult) {
                return this.renewToken().pipe(
                    tap((tokenResult)=> {
                        // Your example never uses tokenResult for anything ...
                        // so I'll assume you actually want tokenResult to bubble
                        // up all the way your component as the result ...
                        this.renewTokenCallback(); // This makes no sense to me ...
                                                   // why have a callback here?
                    }),
                    catchError((tokenError) => {
                        // add code to handle renewToken() returning an error 
                        return tokenError;
                    })
                )
            }
            else {
                // return something that can be handled inside the component 
                // when callbackResult is false.
                // for example:
                return throwError('callbackResult is false');
            }
        })
    )
}

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

  • Общая структура такова, что, когда компонент подписывается на эту цепочку, initializeRegistration() станет исходной (или внешней) наблюдаемой, которая отбрасывает вещии после его завершения renewToken() будет отображен в цепочку и предоставит окончательный результат в качестве возвращаемого токена.
  • Начните с оператора return, потому что эта функция будет посвящена настройке одной наблюдаемойцепочка, которая возвращается и на которую можно подписаться из компонента.
  • Далее начнем с initializeRegistration().После подписки компонента эта функция будет выполнена, и цепочка будет ожидать продолжения, пока не завершится (или не выдаст ошибку).
  • Далее проверьте наличие ошибки.Это необходимо сделать на этом этапе, потому что мы собираемся отобразить (изменить) наблюдаемое в цепочке с помощью mergeMap, поэтому перед тем, как мы это сделаем, мы проверим источник наблюдаемого на наличие ошибок и исправим их.
  • Далее, mergeMap,Этот оператор заботится о «подписке вверх», неявно подписываясь на initializeRegistration, когда он, в свою очередь, подписывается компонентом, поэтому нам не нужен этот вложенный шаблон подписки в вашей исходной функции.Этот оператор также отображает новое наблюдаемое (в данном случае возвращаемое значение из renewToken() в нашу цепочку. Поэтому мы больше не проходим по match, теперь мы проходим по tokenResult в цепочке.
  • Прежде чем поместить результат обратно в основную цепочку, мы передадим это через два дополнительных оператора (я делаю это здесь, в подцепи, а не в главной цепочке из-за логики if-else):
  • Firstоператор субцепи - tap. Здесь я действительно не понимаю вашу бизнес-логику и могу ошибаться в этом. Потому что касание на самом деле не влияет на цепочку, а просто дает нам точку вставки, где мы можемвыполнить какой-то побочный эффект, это то, что я решил назвать renewTokenCallback(). В зависимости от того, что эта функция делает, это может быть неправильным способом справиться с этим ...
  • Следующий оператор суб-цепочки это catchError, это проверка на ошибки из renewToken()
  • Теперь выполняется с подцепью, которая возвращается и снова возвращается к главной цепочке
  • Finсоюзник - это else - важно, чтобы мы возвращали фактическую наблюдаемую изнутри эту область, которую можно объединить обратно в основную цепочку.Что это за наблюдаемое должно быть неясно - какое-то сообщение вплоть до компонента, сообщающее, что что-то пошло не так в callbackResult

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...