@euirim/microsoft-cognitiveservices-speech-sdk
Version:
Microsoft Cognitive Services Speech SDK for JavaScript
180 lines (178 loc) • 8.13 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { InvalidOperationError, ObjectDisposedError } from "./Error";
import { List } from "./List";
import { Deferred, PromiseHelper } from "./Promise";
var SubscriberType;
(function (SubscriberType) {
SubscriberType[SubscriberType["Dequeue"] = 0] = "Dequeue";
SubscriberType[SubscriberType["Peek"] = 1] = "Peek";
})(SubscriberType || (SubscriberType = {}));
export class Queue {
constructor(list) {
this.privPromiseStore = new List();
this.privIsDrainInProgress = false;
this.privIsDisposing = false;
this.privDisposeReason = null;
this.enqueue = (item) => {
this.throwIfDispose();
this.enqueueFromPromise(PromiseHelper.fromResult(item));
};
this.enqueueFromPromise = (promise) => {
this.throwIfDispose();
this.privPromiseStore.add(promise);
promise.finally(() => {
while (this.privPromiseStore.length() > 0) {
if (!this.privPromiseStore.first().result().isCompleted) {
break;
}
else {
const p = this.privPromiseStore.removeFirst();
if (!p.result().isError) {
this.privList.add(p.result().result);
}
else {
// TODO: Log as warning.
}
}
}
});
};
this.dequeue = () => {
this.throwIfDispose();
const deferredSubscriber = new Deferred();
if (this.privSubscribers) {
this.privSubscribers.add({ deferral: deferredSubscriber, type: SubscriberType.Dequeue });
this.drain();
}
return deferredSubscriber.promise();
};
this.peek = () => {
this.throwIfDispose();
const deferredSubscriber = new Deferred();
const subs = this.privSubscribers;
if (subs) {
this.privSubscribers.add({ deferral: deferredSubscriber, type: SubscriberType.Peek });
this.drain();
}
return deferredSubscriber.promise();
};
this.length = () => {
this.throwIfDispose();
return this.privList.length();
};
this.isDisposed = () => {
return this.privSubscribers == null;
};
this.drainAndDispose = (pendingItemProcessor, reason) => {
if (!this.isDisposed() && !this.privIsDisposing) {
this.privDisposeReason = reason;
this.privIsDisposing = true;
const subs = this.privSubscribers;
if (subs) {
while (subs.length() > 0) {
const subscriber = subs.removeFirst();
// TODO: this needs work (Resolve(null) instead?).
subscriber.deferral.resolve(undefined);
// subscriber.deferral.reject("Disposed");
}
// note: this block assumes cooperative multitasking, i.e.,
// between the if-statement and the assignment there are no
// thread switches.
// Reason is that between the initial const = this.; and this
// point there is the derral.resolve() operation that might have
// caused recursive calls to the Queue, especially, calling
// Dispose() on the queue alredy (which would reset the var
// here to null!).
// That should generally hold true for javascript...
if (this.privSubscribers === subs) {
this.privSubscribers = subs;
}
}
for (const detachable of this.privDetachables) {
detachable.detach();
}
if (this.privPromiseStore.length() > 0 && pendingItemProcessor) {
return PromiseHelper
.whenAll(this.privPromiseStore.toArray())
.continueWith(() => {
this.privSubscribers = null;
this.privList.forEach((item, index) => {
pendingItemProcessor(item);
});
this.privList = null;
return true;
});
}
else {
this.privSubscribers = null;
this.privList = null;
}
}
return PromiseHelper.fromResult(true);
};
this.dispose = (reason) => {
this.drainAndDispose(null, reason);
};
this.drain = () => {
if (!this.privIsDrainInProgress && !this.privIsDisposing) {
this.privIsDrainInProgress = true;
const subs = this.privSubscribers;
const lists = this.privList;
if (subs && lists) {
while (lists.length() > 0 && subs.length() > 0 && !this.privIsDisposing) {
const subscriber = subs.removeFirst();
if (subscriber.type === SubscriberType.Peek) {
subscriber.deferral.resolve(lists.first());
}
else {
const dequeuedItem = lists.removeFirst();
subscriber.deferral.resolve(dequeuedItem);
}
}
// note: this block assumes cooperative multitasking, i.e.,
// between the if-statement and the assignment there are no
// thread switches.
// Reason is that between the initial const = this.; and this
// point there is the derral.resolve() operation that might have
// caused recursive calls to the Queue, especially, calling
// Dispose() on the queue alredy (which would reset the var
// here to null!).
// That should generally hold true for javascript...
if (this.privSubscribers === subs) {
this.privSubscribers = subs;
}
// note: this block assumes cooperative multitasking, i.e.,
// between the if-statement and the assignment there are no
// thread switches.
// Reason is that between the initial const = this.; and this
// point there is the derral.resolve() operation that might have
// caused recursive calls to the Queue, especially, calling
// Dispose() on the queue alredy (which would reset the var
// here to null!).
// That should generally hold true for javascript...
if (this.privList === lists) {
this.privList = lists;
}
}
this.privIsDrainInProgress = false;
}
};
this.throwIfDispose = () => {
if (this.isDisposed()) {
if (this.privDisposeReason) {
throw new InvalidOperationError(this.privDisposeReason);
}
throw new ObjectDisposedError("Queue");
}
else if (this.privIsDisposing) {
throw new InvalidOperationError("Queue disposing");
}
};
this.privList = list ? list : new List();
this.privDetachables = [];
this.privSubscribers = new List();
this.privDetachables.push(this.privList.onAdded(this.drain));
}
}
//# sourceMappingURL=Queue.js.map