Skip to content

Instantly share code, notes, and snippets.

@jamesknelson
Last active March 20, 2019 06:15
Show Gist options
  • Save jamesknelson/314cb2c9d9b5c63b25e3f446111bbffc to your computer and use it in GitHub Desktop.
Save jamesknelson/314cb2c9d9b5c63b25e3f446111bbffc to your computer and use it in GitHub Desktop.

mapObservableToChunkIterator(observable, mapValueToChunks, mapErrorToChunks?): Generator<Promise | Chunk[]>

A function that accepts an Observable with a subscribe() method, and optionally with a getCurrentValue() or getCurrentResult() method.

It returns a Generator that yields Promise (when waiting for a new value) or Chunk objects (i.e. objects that extend { type: string }).

By default, mapErrorToChunks takes the error emitted by an observable, and yields [{ type: 'error', error: error }].

When the observable is complete, the Generator's next() function will return { done: true }.

Use finally to unsubscribe it then return without yielding anything. For more details, see: https://hacks.mozilla.org/2015/07/es6-in-depth-generators-continued/

interface Chunk {
  type: string | number | Symbol
}

function* mapObservableToChunkIterator<T, ValueChunk extends Chunk, ErrorChunk extends Chunk>(
  observable: Observable<T>, 
  mapValueToChunks: (value: T) => ValueChunk[],
  mapErrorToChunks?: (value: T) => ErrorChunk[]
): Generator<Promise<void> | Chunk[]> {
  // This isn't standardized, so try common names
  let getValue = observable.getCurrentValue || observable.getCurrentResult || observable.getValue
  
  // If the observable provides a way to get the current value, yield it immediately
  if (getValue) {
    let initialValue = getValue.call(observable)
    yield mapValueToChunks(initialValue)
  }

  // Subscribe to the observable
  let subscription = observable.subscribe(
    // ...
  )

  try {
    do {
      // Yield a promise that resolves when a value or error or complete callback is called
      yield nextValuePromise

      // Then yield the actual value
      yield chunks
    }
  }
  // Use finally to ensure that unsubscribe is called (as ES6 generators
  // will call their finally block if you call `.return()` on the
  // returned generator object).
  finally {
    subscription.unsubscribe()
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment