Skip to content

Instantly share code, notes, and snippets.

@aayla-secura
Created September 2, 2024 07:12
Show Gist options
  • Save aayla-secura/af0cab39341ef0c4ec7fcf5dc9927c15 to your computer and use it in GitHub Desktop.
Save aayla-secura/af0cab39341ef0c4ec7fcf5dc9927c15 to your computer and use it in GitHub Desktop.
Promise with state and result properties for synchronous inspection
// credit: https://stackoverflow.com/a/46647783/8457586
const newStatefulPromise = (executor, ...args) => {
let currentState = "pending";
let currentResult;
let promise;
const setResult = (state, result) => {
if (currentState !== "pending") {
return;
}
if (promise) {
// executor had run asynchronously
promise.state = state;
promise.result = result;
} else {
// executor had run synchronously, promise not yet assigned
currentState = state;
currentResult = result;
}
};
const wrapper = (resolve, reject) => {
const resolveWrapper = (result) => {
if (result instanceof Promise) {
result.then(resolveWrapper).catch(rejectWrapper);
} else {
setResult("resolved", result);
resolve(result);
}
};
const rejectWrapper = (result) => {
if (result instanceof Promise) {
// always reject
result.then(rejectWrapper).catch(rejectWrapper);
} else {
setResult("rejected", result);
reject(result);
}
};
executor(...args, resolveWrapper, rejectWrapper);
};
promise = new Promise(wrapper);
promise.state = currentState;
promise.result = currentResult;
if (currentState === "rejected") {
// executor ran synchronously and rejected; catch it here so that the
// callee does not need to catch it, but can just inspect the state and
// result
promise.catch(() => {});
}
return promise;
};
// Example:
// let p1 = newStatefulPromise((res, rej) => res('foo'));
// console.log(p1.state, p1.result); // fulfilled
//
// let p2 = newStatefulPromise((res, rej) => res(
// new Promise((res) => setTimeout(() => res('foo'), 10))
// ));
// console.log(p2.state, p2.result); // pending
// p2.then(() => console.log(p2.state, p2.result))
//
// let p3 = newStatefulPromise((res, rej) => setTimeout(() => res('foo'), 10));
// console.log(p3.state, p3.result); // pending
// p3.then(() => console.log(p3.state, p3.result))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment