Order of execution with rxjs asapscheduler

1.2k views Asked by At

Considering I have the following code:

let Rx = window['rxjs'];
const { of,
    queueScheduler,
    asapScheduler,
    asyncScheduler,
    animationFrameScheduler
} = Rx;
const { observeOn, tap } = Rx.operators;
console.clear();


let source$ = of(1, 2, 3, asapScheduler).pipe(
    tap((v) => {
        console.log('tap ', v);
    }),
)

source$.subscribe((v) => {
    console.log('Value ', v);
    Promise.resolve().then(() => {
        console.log('Microtask value ', v);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.1/rxjs.umd.js"></script>

Which I use asapScheduler operator.

As per the documentation,

asap will wait for the current synchronously executing code to end and then it will try to execute the given task as fast as possible.

What's the execution order of the above code? How do they work? I would not have expected that the tap3 to print at the last

Below are the output,

tap  1
Value  1  
tap  2    // here why did this not print Microtask value 1 and Microtask value 2 after printing tap1 and value1?
Value  2
Microtask value  1
Microtask value  2
tap  3
Value  3
Microtask value  3
2

There are 2 answers

0
anonymous On BEST ANSWER

Steps involved:

  1. of emits the first value according to the scheduler (the next macrotask in this example)
  2. It puts the next value to the scheduler queue (microtask)
  3. Steps 1 and 2 are repeated with each of the next emissions.

The control prints the current macrotask,

1.) tap1 and value1

as per the second step, 2.) tap2 and value2 are executed and complete all the pending asap and async tasks as below,

3.)Microtask value 1 and Microtask value 2

as per the third step,

it again follows the first step as below,

4.) tap 3 and value 3

and as per the second step, tap4 and value4 are executed and completes all the pending asap and async tasks as below,

Microtask value 3 Microtask value 4

To dive deep refer this article

7
Anton Marinenko On

As I know RxJS tends to standalone schedulers usage. And it works as expected:

let source$ = of(1, 2, 3).pipe(
    tap((v) => {
        console.log('tap ', v);
    }),
)

source$.subscribe((v) => {
    asapScheduler.schedule(() => console.log('Value ', v));
    asyncScheduler.schedule(() => Promise.resolve().then(() => {
        console.log('Microtask value ', v);
    }))
})

Another meaning, if you use scheduler inside your observable, like Of(..., asapScheduler), - it takes full path flow of your observable, from creation up to end of subscription, and trying to invoke it asap. In your example with microtasks, and it's look reasonable.