benlesh / rxjs-for-await

A library for making RxJS support async-await for-await loops via AsyncIterables

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestion: Illustrate the README with examples showing how the loop and Observable interact.

deanrad opened this issue · comments

Ben, thanks for this library. Some benefit of early quarantine days :)

I made a bit of a test suite (in mocha, below) to show myself how it worked. The README was great to show the options for creating iterators, but not for showing how time slicing is treated. Perhaps the "marble diagrams" below are most illustrative of what I think could be helpful for the README, but what you have in the test suite would probably work pretty well in some form.

In any event, FWIW the below conveys to me the ways one could use this library, so thanks for throwing it together. Let me know if you want me to do anything on this..

import { concat, timer } from 'rxjs';
import { take, mapTo } from 'rxjs/operators';
import {
  eachValueFrom,
  nextValueFrom,
  latestValueFrom,
  bufferedValuesFrom,
} from 'rxjs-for-await';

const after = (ms, value) => timer(ms).pipe(mapTo(value))

describe('for-await', () => {
  // 0----1-2----3
  // |------->|------->|------->
  const observed = concat(
      after(0, 0),
      after(8, 1),
      after(2, 2),
      after(10, 3)
  );

  describe('eachValueFrom', () => {
    // 0----1-2----3
    // 0------->|1------>|2------>|3------>
    it('processes serially', async function() {
      const seen = [];

      for await (let v of eachValueFrom(observed)) {
        await after(15);
        seen.push(v);
      }
      expect(seen).to.eql([0, 1, 2, 3]);
    });
  });

  describe('nextValueFrom', () => {
    it('ignores values that arrive during the loop', async function() {
      let seen = [];

      // 0----1-2----3
      //      1------->
      for await (let v of nextValueFrom(observed)) {
        await after(15);
        seen.push(v);
      }
      expect(seen).to.eql([1]);
      seen = [];

      // 0----1-2----3
      //      1--->3---->
      for await (let v of nextValueFrom(observed)) {
        await after(8);
        seen.push(v);
      }
      expect(seen).to.eql([1, 3]);
    });
  });

  describe('latestValueFrom', () => {
    // 0----1-2----3
    // 0------->|2------>|3------>
    it('ignores all but the last value during the loop', async function() {
      const seen = [];

      for await (let v of latestValueFrom(observed)) {
        await after(15);
        seen.push(v);
      }
      expect(seen).to.eql([0, 2, 3]);
    });
  });

  describe('bufferedValuesFrom', () => {
    // 0----1-2----3
    // 0------->|1,2------>|3------>
    it('yields batches serially', async function() {
      const seen = [];

      for await (let v of bufferedValuesFrom(observed)) {
        await after(15);
        seen.push(v);
      }
      expect(seen).to.eql([[0], [1, 2], [3]]);
    });
  });
});

Also would like to understand the unsubscription too. Te underlying code does an unsubscribe in a finally block, so it seems that unsubscription might be automatic, but just wanting confirmation of that before considering using it in a app where the use of unsubscribe makes a great difference in stability and performance.