Skip to content

Instantly share code, notes, and snippets.

@atengberg
Last active August 22, 2024 11:01
Show Gist options
  • Save atengberg/aae531393607719449f872b0aa151ef4 to your computer and use it in GitHub Desktop.
Save atengberg/aae531393607719449f872b0aa151ef4 to your computer and use it in GitHub Desktop.
Generically wrap a stream of data values as an thenble-like async iterator

Find yourself with a callback you'd like to make its passed values iterable--ie useful in a for await loop?

function Streamer(key) {
  const _ = Object.create(null);
  _.key = key;
  _.resolver = null;
  _.dataQueue = [];
  const push = function (newData) {
    if (this.resolver) {
      this.resolver({ value: newData, done: false });
      this.resovler = null;
    } else {
      this.dataQueue.push(newData);
    }
  }.bind(_);
  const pull = function () {
    const self = this;
    return new Promise((r) => {
      if (self.dataQueue.length) {
        r({ value: self.dataQueue.shift(), done: false });
      } else {
        self.resolver = r;
      }
    });
  }.bind(_);
  return {
    push,
    pull,
    [Symbol.asyncIterator]() {
      return {
        next: this.pull,
      };
    },
  };
}

Now can be used to create Readable wrapped data sources so that the data ca... must flow.

Best way to handle error/rejection case? Note while there are many settled resolutions, should only need to be one rejection else restart.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment