mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-27 01:22:49 +00:00
363 lines
9.1 KiB
JavaScript
363 lines
9.1 KiB
JavaScript
"use strict";
|
|
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();
|
|
}
|
|
}
|