Skip to content

Instantly share code, notes, and snippets.

@jordangarcia
Created May 23, 2025 18:28
Show Gist options
  • Save jordangarcia/e787360ea06417aef7c3ae3733f78b98 to your computer and use it in GitHub Desktop.
Save jordangarcia/e787360ea06417aef7c3ae3733f78b98 to your computer and use it in GitHub Desktop.
class CustomPromise<R> {
private status: 'awaiting' | 'resolved' | 'rejected' = 'awaiting';
private resolvedValue: R | undefined = undefined;
private rejectedReason: unknown = undefined;
private successFns: ((val: R) => void)[] = [];
private rejectFns: ((reason: unknown) => void)[] = [];
static resolve<SR>(val: SR): CustomPromise<SR> {
return new CustomPromise<SR>(r => r(val));
}
static reject<SR>(rejectedReason: SR): CustomPromise<never> {
return new CustomPromise<never>((_, r) => r(rejectedReason));
}
constructor(executorFn: (resolve: (val: R) => void, reject: (reason: unknown) => void) => void) {
setTimeout(() => {
executorFn(this.resolve.bind(this), this.reject.bind(this));
}, 0);
}
private resolve(val: R) {
if (this.status === 'awaiting') {
this.status = 'resolved';
this.resolvedValue = val;
this.successFns.forEach(fn => fn(val));
}
}
private reject(reason: unknown) {
if (this.status === 'awaiting') {
this.rejectFns.forEach(fn => fn(reason));
this.rejectedReason = reason;
this.status = 'rejected';
}
}
then<NR, Nunknown>(
resolveFn: (val: R) => NR,
rejectFn?: (reason: unknown) => unknown
): CustomPromise<NR> {
return new CustomPromise<NR>((resolve, reject) => {
if (this.status === 'resolved') {
resolve(resolveFn(this.resolvedValue!));
return;
}
if (this.status === 'rejected' && rejectFn) {
reject(rejectFn(this.rejectedReason!));
return;
}
this.successFns.push(resolveValue => {
const results = resolveFn(resolveValue);
// if this is a promise await it
if (results && typeof results === 'object' && 'then' in results) {
const resultIsPromise = results as any as CustomPromise<any>;
resultIsPromise.then(resolve, reject);
return;
} else {
resolve(results);
}
});
if (rejectFn) {
this.rejectFns.push(rejectReason => {
const results = rejectFn(rejectReason);
if (results && typeof results === 'object' && 'then' in results) {
const resultIsPromise = results as any as CustomPromise<any>;
resultIsPromise.then(resolve, reject);
return;
} else {
reject(results);
}
});
}
});
}
}
async function main() {
const promise = new CustomPromise<string>((resolve, reject) => {
setTimeout(() => {
resolve('hello');
}, 100);
});
const waitwaitwait = promise.then(val => {
console.log('then value', val);
return 'transformed';
});
const a = await waitwaitwait;
console.log(a);
promise.then(v => {
console.log('already resolved', v);
});
}
await main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment