Some time ago I had a really simple, but really tricky situation. I wanted to do some action before async pipe would subscribed given observable. In short - I’m going to show you how to run something just before observable subscription is created.

<my-component [data]="data$ | async"></my-component>
@Component({
  selector: 'app',
  templateUrl: './app.html',
  styleUrls: ['./app.scss'],
})
export class Foo implements OnInit {
    
  data$: Observable<any>;

  ngOnInit() {
    this.data$ = // .... get observable from some service
    
    this.showLoader();
    this.data$ = this.data$.pipe(finalize(() => {
      console.log('Mhmm');
    }));
  }
}

What is wrong with above approach?

If you go with this direction it might caused a few unexpected behaviours. The main thing is that you will show loader at the moment of component initialization, not at the moment of observable subscription. The right way to doing things here to use defer operator.


defer(observableFactory: function(): SubscribableOrPromise): Observable


What does defer do? It’s executing action just before subscription is created - that’s it. So, how to fix last example?

@Component({
  selector: 'app',
  templateUrl: './app.html',
  styleUrls: ['./app.scss'],
})
export class Foo implements OnInit {
    
  data$: Observable<any>;

  ngOnInit() {
    this.data$ = // .... get observable from some service
    
    this.data$ = defer(() => {
      this.showLoader();
      return this.data$.pipe(finalize(() => {
        console.log('Yeach');
      }));
    });
  }
}