nx
Version:
363 lines (362 loc) • 9.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Deferred = void 0;
exports.eachValueFrom = eachValueFrom;
exports.bufferedValuesFrom = bufferedValuesFrom;
exports.latestValueFrom = latestValueFrom;
exports.nextValueFrom = nextValueFrom;
class Deferred {
constructor() {
this.resolve = null;
this.reject = null;
this.promise = new Promise((a, b) => {
this.resolve = a;
this.reject = b;
});
}
}
exports.Deferred = Deferred;
const RESOLVED = Promise.resolve();
/**
* Will subscribe to the `source` observable provided,
*
* Allowing a `for await..of` loop to iterate over every
* value that the source emits.
*
* **WARNING**: If the async loop is slower than the observable
* producing values, the values will build up in a buffer
* and you could experience an out of memory error.
*
* This is a lossless subscription method. No value
* will be missed or duplicated.
*
* Example usage:
*
* ```ts
* async function test() {
* const source$ = getSomeObservable();
*
* for await(const value of eachValueFrom(source$)) {
* console.log(value);
* }
* }
* ```
*
* @param source the Observable source to await values from
*/
async function* eachValueFrom(source) {
const deferreds = [];
const values = [];
let hasError = false;
let error = null;
let completed = false;
const subs = source.subscribe({
next: (value) => {
if (deferreds.length > 0) {
deferreds.shift().resolve({ value, done: false });
}
else {
values.push(value);
}
},
error: (err) => {
hasError = true;
error = err;
while (deferreds.length > 0) {
deferreds.shift().reject(err);
}
},
complete: () => {
completed = true;
while (deferreds.length > 0) {
deferreds.shift().resolve({ value: undefined, done: true });
}
},
});
try {
while (true) {
if (values.length > 0) {
yield values.shift();
}
else if (completed) {
return;
}
else if (hasError) {
throw error;
}
else {
const d = new Deferred();
deferreds.push(d);
const result = await d.promise;
if (result.done) {
return;
}
else {
yield result.value;
}
}
}
}
catch (err) {
throw err;
}
finally {
subs.unsubscribe();
}
}
/**
* Will subscribe to the `source` observable provided
* and build the emitted values up in a buffer. Allowing
* `for await..of` loops to iterate and get the buffer
* on each loop.
*
* This is a lossless subscription method. No value
* will be missed or duplicated.
*
* Example usage:
*
* ```ts
* async function test() {
* const source$ = getSomeObservable();
*
* for await(const buffer of bufferedValuesFrom(source$)) {
* for (const value of buffer) {
* console.log(value);
* }
* }
* }
* ```
*
* @param source the Observable source to await values from
*/
async function* bufferedValuesFrom(source) {
let deferred = null;
const buffer = [];
let hasError = false;
let error = null;
let completed = false;
const subs = source.subscribe({
next: (value) => {
if (deferred) {
deferred.resolve(RESOLVED.then(() => {
const bufferCopy = buffer.slice();
buffer.length = 0;
return { value: bufferCopy, done: false };
}));
deferred = null;
}
buffer.push(value);
},
error: (err) => {
hasError = true;
error = err;
if (deferred) {
deferred.reject(err);
deferred = null;
}
},
complete: () => {
completed = true;
if (deferred) {
deferred.resolve({ value: undefined, done: true });
deferred = null;
}
},
});
try {
while (true) {
if (buffer.length > 0) {
const bufferCopy = buffer.slice();
buffer.length = 0;
yield bufferCopy;
}
else if (completed) {
return;
}
else if (hasError) {
throw error;
}
else {
deferred = new Deferred();
const result = await deferred.promise;
if (result.done) {
return;
}
else {
yield result.value;
}
}
}
}
catch (err) {
throw err;
}
finally {
subs.unsubscribe();
}
}
/**
* Will subscribe to the provided `source` observable,
* allowing `for await..of` loops to iterate and get the
* most recent value that was emitted. Will not iterate out
* the same emission twice.
*
* This is a lossy subscription method. Do not use if
* every value is important.
*
* Example usage:
*
* ```ts
* async function test() {
* const source$ = getSomeObservable();
*
* for await(const value of latestValueFrom(source$)) {
* console.log(value);
* }
* }
* ```
*
* @param source the Observable source to await values from
*/
async function* latestValueFrom(source) {
let deferred = undefined;
let latestValue;
let hasLatestValue = false;
let hasError = false;
let error = null;
let completed = false;
const subs = source.subscribe({
next: (value) => {
hasLatestValue = true;
latestValue = value;
if (deferred) {
deferred.resolve(RESOLVED.then(() => {
hasLatestValue = false;
return { value: latestValue, done: false };
}));
}
},
error: (err) => {
hasError = true;
error = err;
if (deferred) {
deferred.reject(err);
}
},
complete: () => {
completed = true;
if (deferred) {
hasLatestValue = false;
deferred.resolve({ value: undefined, done: true });
}
},
});
try {
while (true) {
if (hasLatestValue) {
await RESOLVED;
const value = latestValue;
hasLatestValue = false;
yield value;
}
else if (completed) {
return;
}
else if (hasError) {
throw error;
}
else {
deferred = new Deferred();
const result = await deferred.promise;
if (result.done) {
return;
}
else {
yield result.value;
}
}
}
}
catch (err) {
throw err;
}
finally {
subs.unsubscribe();
}
}
/**
* Subscribes to the provided `source` observable and allows
* `for await..of` loops to iterate over it, such that
* all values are dropped until the iteration occurs, then
* the very next value that arrives is provided to the
* `for await` loop.
*
* This is a lossy subscription method. Do not use if
* every value is important.
*
* Example usage:
*
* ```ts
* async function test() {
* const source$ = getSomeObservable();
*
* for await(const value of nextValueFrom(source$)) {
* console.log(value);
* }
* }
* ```
*
* @param source the Observable source to await values from
*/
async function* nextValueFrom(source) {
let deferred = undefined;
let hasError = false;
let error = null;
let completed = false;
const subs = source.subscribe({
next: (value) => {
if (deferred) {
deferred.resolve({ value, done: false });
}
},
error: (err) => {
hasError = true;
error = err;
if (deferred) {
deferred.reject(err);
}
},
complete: () => {
completed = true;
if (deferred) {
deferred.resolve({ value: undefined, done: true });
}
},
});
try {
while (true) {
if (completed) {
return;
}
else if (hasError) {
throw error;
}
else {
deferred = new Deferred();
const result = await deferred.promise;
if (result.done) {
return;
}
else {
yield result.value;
}
}
}
}
catch (err) {
throw err;
}
finally {
subs.unsubscribe();
}
}
;