export default class MutablePromise extends Promise {
constructor(executor, ...constructorArguments) {
console.assert(arguments.length === 0 || typeof executor === "function", executor);
let builtinResolve = null;
let builtinReject = null;
let status = MutablePromise.Status.Pending;
let result = undefined;
function setStatus(newStatus, builtinResult) {
console.assert(Object.values(MutablePromise.Status).includes(newStatus), newStatus);
console.assert(Array.isArray(builtinResult), builtinResult);
console.assert(newStatus !== MutablePromise.Status.Pending, newStatus);
if (status !== MutablePromise.Status.Pending)
return;
status = newStatus;
result = builtinResult;
}
super(function(resolve, reject, ...executorArguments) {
builtinResolve = resolve;
builtinReject = reject;
executor?.(
function(...builtinResult) {
setStatus(MutablePromise.Status.Resolved, builtinResult);
return builtinResolve(...builtinResult);
},
function(...builtinResult) {
setStatus(MutablePromise.Status.Rejected, builtinResult);
return builtinReject(...builtinResult);
},
...executorArguments
);
}, ...constructorArguments);
this._resolve = builtinResolve;
this._reject = builtinReject;
this._status = MutablePromise.Status.Pending;
if (status !== MutablePromise.Status.Pending)
this._setStatus(status, result);
console.assert(status === this._status, executor, ...constructorArguments);
}
// Public
get status() { return this._status; }
resolve(...result) {
this._setStatus(MutablePromise.Status.Resolved, result);
return this._resolve(...result);
}
reject(...result) {
this._setStatus(MutablePromise.Status.Rejected, result);
return this._reject(...result);
}
// Protected
get result() { return this._result; }
// Private
_setStatus(status, result) {
console.assert(Object.values(MutablePromise.Status).includes(status), status);
console.assert(Array.isArray(result), result);
console.assert(status !== MutablePromise.Status.Pending, status);
if (this._status !== MutablePromise.Status.Pending)
return;
this._status = status;
this._result = result;
let property = null;
switch (this._status) {
case MutablePromise.Status.Resolved:
property = "value";
break;
case MutablePromise.Status.Rejected:
property = "reason";
break;
}
console.assert(property, this._status);
Object.defineProperty(this, property, {
value: this._result[0],
enumerable: true,
});
}
}
MutablePromise.Status = {
Pending: Symbol("promise-status-pending"),
Resolved: Symbol("promise-status-resolved"),
Rejected: Symbol("promise-status-rejected"),
};