axax
Version:
A library of async iterator extensions for JavaScript including ```map```, ```reduce```, ```filter```, ```flatMap```, ```pipe``` and [more](https://github.com/jamiemccrindle/axax/blob/master/docs/API.md#functions).
121 lines (120 loc) • 3.93 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const deferred_1 = require("./deferred");
/**
* The async iterator equivalent of a deferred
*/
class Subject {
constructor() {
this.doneValue = {
done: true,
value: {}
};
this.queue = [];
this.deferreds = [];
this.done = false;
this.noMoreResults = false;
this.backPressureDeferred = new deferred_1.Deferred();
this.finallyCallbacks = [];
this.error = undefined;
const self = this;
this.iterator = {
throw(e) {
self.done = true;
self.finallyCallbacks.map(cb => cb());
// fail any waiting deferreds
for (const deferred of self.deferreds) {
deferred.reject(e);
}
return Promise.reject(e);
},
return(value) {
self.done = true;
self.finallyCallbacks.map(cb => cb());
// fail any waiting deferreds
for (const deferred of self.deferreds) {
deferred.resolve({
done: true,
value: {}
});
}
return Promise.resolve(self.doneValue);
},
next(value) {
if (self.error) {
return Promise.reject(self.error);
}
const queuedItem = self.queue.shift();
if (self.queue.length === 0) {
self.backPressureDeferred.resolve();
self.backPressureDeferred = new deferred_1.Deferred();
}
if (queuedItem !== undefined) {
return Promise.resolve(queuedItem);
}
else {
if (self.noMoreResults && !self.done) {
self.done = true;
self.finallyCallbacks.map(cb => cb());
}
if (self.done) {
return Promise.resolve({
done: true,
value: {}
});
}
const deferred = new deferred_1.Deferred();
self.deferreds.push(deferred);
return deferred.promise;
}
},
[Symbol.asyncIterator]() {
return this;
}
};
}
finally(callback) {
this.finallyCallbacks.push(callback);
}
onCompleted() {
return this.callback({ done: true, value: {} });
}
onNext(value) {
return this.callback({ done: false, value });
}
onError(error) {
this.error = error;
for (const queuedDeferred of this.deferreds) {
queuedDeferred.reject(error);
}
this.noMoreResults = true;
}
isDone() {
return this.done;
}
callback(result) {
if (!(this && this instanceof Subject)) {
const errorMessage = "This must be a Subject. Have you bound this?";
// tslint:disable-next-line:no-console
console.log(errorMessage);
throw new Error(errorMessage);
}
if (result.done) {
for (const queuedDeferred of this.deferreds) {
queuedDeferred.resolve(result);
}
this.noMoreResults = true;
return Promise.resolve();
}
const deferred = this.deferreds.pop();
if (deferred !== undefined) {
deferred.resolve(result);
return Promise.resolve();
}
else {
this.queue.push(result);
return this.backPressureDeferred.promise;
}
}
}
exports.Subject = Subject;