Angular asynchronous data flow programming

1 Several common methods of asynchronous programming

First give an example of an asynchronous request:

import {<!-- -->Injectable} from '@angular/core';

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData() {<!-- -->
    setTimeout(() => {<!-- -->
      let res = 'zhaoshuai-lc'
      return res
    }, 3000)
  }
}

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit{<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    let data = this.RequestServiceService.getData()
    console.log(data)
  }
}

1.1 Callback function to solve problems

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit{<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    this.RequestServiceService.getData(data => {<!-- -->
      console.log(data)
    })
  }
}

import {<!-- -->Injectable} from '@angular/core';

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData(callBack) {<!-- -->
    setTimeout(() => {<!-- -->
      let res = 'zhaoshuai-lc'
      callBack(res)
    }, 3000)
  }
}

1.2 Promise processing asynchronously

import {<!-- -->Injectable} from '@angular/core';

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData() {<!-- -->
    return new Promise((resolve, reject) => {<!-- -->
      setTimeout(() => {<!-- -->
        let res = 'zhaoshuai-lc'
        resolve(res)
      }, 3000)
    })

  }
}

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    let promiseData = this.RequestServiceService.getData()
    promiseData.then(data => {<!-- -->
      console.log(data)
    })
  }
}

1.3 RxJS handles asynchronous

import {<!-- -->Injectable} from '@angular/core';
import {<!-- -->Observable} from "rxjs";

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData() {<!-- -->
    return new Observable(observer => {<!-- -->
      setTimeout(() => {<!-- -->
        let res = 'zhaoshuai-lc'
        observer.next(res)
      }, 3000)
    })
  }
}

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    let observableData = this.RequestServiceService.getData()
    observableData.subscribe(data => {<!-- -->
      console.log(data)
    })
  }
}

From the above example, you can see that the basic usage of RxJS and Promise are very similar, except for some different keywords. Then() and resolve() are used in Promise, while next() and subscribe() are used in RxJS.

From the above examples, we feel that the usage of Promise and RxJS are basically similar. In fact, Rxjs is much more powerful than Promise. For example, Rxjs can be withdrawn midway, Rxjs can emit multiple values, Rxjs provides a variety of tool functions, etc.

2 Rxjs unsubscribe cancel subscription

After a Promise is created, the action cannot be undone. Observable is different. Actions can be withdrawn midway through the unsbscribe() method, and Observable does intelligent processing internally.

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    //Retract after one second
    let stream = this.RequestServiceService.getData()
    let res = stream.subscribe(data => {<!-- -->
      console.log(data)
    })
    setTimeout(() => {<!-- -->
      console.log('Unsubscribed')
      res.unsubscribe()
    }, 1000)
  }
}

3 Rxjs executed multiple times after subscription

If we want the asynchronous method to be executed multiple times, Promise cannot do this. For Promise, the final result is either resolve (fulfillment) or reject (rejection), and both can only be triggered once. If the resolve method is called multiple times on the same Promise object, an exception will be thrown. Observable is different, it can continuously trigger the next value, as the name of the next() method implies.

import {<!-- -->Injectable} from '@angular/core';
import {<!-- -->Observable} from "rxjs";

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData() {<!-- -->
    return new Observable(observer => {<!-- -->
      setInterval(() => {<!-- -->
        let res = 'zhaoshuai-lc'
        observer.next(res)
      }, 1000)
    })
  }
}

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    let stream = this.RequestServiceService.getData()
    let res = stream.subscribe(data => {<!-- -->
      console.log(data)
    })
  }
}

4 After Angualr6.x, use Rxjs tool functions map, filter

import {<!-- -->Injectable} from '@angular/core';
import {<!-- -->Observable} from "rxjs";

@Injectable({<!-- -->
  providedIn: 'root'
})
export class RequestServiceService {<!-- -->

  constructor() {<!-- -->
  }

  getData() {<!-- -->
    return new Observable(observer => {<!-- -->
      let count = 0;
      setInterval(() => {<!-- -->
        count++
        observer.next(count)
      }, 1000)
    })
  }
}

import {<!-- -->Component, OnInit} from '@angular/core';
import {<!-- -->RequestServiceService} from "./services/request-service.service";
import {<!-- -->filter, map} from 'rxjs/operators';

@Component({<!-- -->
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {<!-- -->

  constructor(public RequestServiceService: RequestServiceService) {<!-- -->
  }

  ngOnInit(): void {<!-- -->
    let stream = this.RequestServiceService.getData()
    stream.pipe(
      filter(value => Number(value) % 2 == 0),
      map(value => Number(value) * Number(value))
    ).subscribe(data => {<!-- -->
      console.log(data)
    })
  }
}