Home > Software design >  How to discard observable that has not been returned
How to discard observable that has not been returned

Time:05-20

The user clicks the first page and then the second page. Due to the different return time of the request, a bug is caused, resulting in the user finally seeing the data on the first page.

I want to discard the incomplete observable. Is there a corresponding Operator?

The correct result of the following example should only output 2

import { Observable } from "rxjs";

let time = null;

const o = new Observable((s) => {
  setTimeout(() => {
    s.next();
  }, time);
}).pipe(); // <- I think I should add something

function render (pageNumber) {
  o.subscribe(() => {
    console.log(`Render page ${pageNumber}`);
  });
}
// The user wants to see the first page
time = 2000;
render(1);

// After 1ms...
// The user wants to see the second page
time = 1;
render(2);

// Due to the different return time of the request:
// 1. the first page returns in 2 seconds
// 2. the econd page returns in 1ms
// As a result, the second page is rendered first, and then the first page is rendered. The user finally sees the first page.This is wrong and the user should see the second page.

CodePudding user response:

I suppose timer is something that you assign randomly to simulate api request time. The following pattern is better, when next page request comes in, with switchMap it'll cancel the previous one

render
  .pipe(switchMap((obj: any) => timer(obj.time).pipe(mapTo(obj.page))))
  .subscribe(console.log);

render.next({ time: 2000, page: 1 });
//request for page 2 immediately 
render.next({ time: 1, page: 2 });
//request for page 3 after 3 second
setTimeout(() => render.next({ time: 1000, page: 3 }), 3000);

In above example you will only see page 2 and 3 print to console. https://stackblitz.com/edit/rxjs-g5e5zf?file=index.ts

CodePudding user response:

Your example is a bit weird. If you set a async action (your timeOut) inside your Observable creation and call next with inside it, your observable will emit based on how long the async action takes. I think you're looking for switchMap in this case.

Example (not tested):


// Create observable
const _a$ = new Subject();
const a$ = _a$.pipe(

    // User input so maybe wait a bit first for user to be done clicking
    debounceTime(100),

    // Then switchMap to cancel previous and switch to the new result you want
    switchMap(async x => {

        // Do some async page rendering
        return new Promise(resolve => setTimeout(() => {
            resolve();
        }, 2000));

    })
);


a$.subscribe();

// The user wants to see the first page
_a$.next(1);

// The user wants to see the second page
_a$.next(2);

  • Related