feat: implement basic promises
This commit is contained in:
parent
7423e3f283
commit
1ac68425af
@ -14,6 +14,7 @@ import { Math as _Math } from "./math.ts";
|
|||||||
import { Set, WeakSet } from "./set.ts";
|
import { Set, WeakSet } from "./set.ts";
|
||||||
import { JSON } from "./json.ts";
|
import { JSON } from "./json.ts";
|
||||||
import { encodeURI, encodeURIComponent } from "./url.ts";
|
import { encodeURI, encodeURIComponent } from "./url.ts";
|
||||||
|
import { Promise } from "./promise.ts";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
function print(...args: any[]): void;
|
function print(...args: any[]): void;
|
||||||
@ -22,7 +23,7 @@ declare global {
|
|||||||
|
|
||||||
function fixup<T extends Function>(clazz: T) {
|
function fixup<T extends Function>(clazz: T) {
|
||||||
object.setPrototype(clazz, Function.prototype);
|
object.setPrototype(clazz, Function.prototype);
|
||||||
object.setPrototype(clazz.prototype, Object.prototype);
|
object.setPrototype(clazz.prototype as any, Object.prototype);
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ target.Set = fixup(Set);
|
|||||||
target.WeakSet = fixup(WeakSet);
|
target.WeakSet = fixup(WeakSet);
|
||||||
target.RegExp = fixup(RegExp);
|
target.RegExp = fixup(RegExp);
|
||||||
target.Date = fixup(Date);
|
target.Date = fixup(Date);
|
||||||
|
target.Promise = fixup(Promise);
|
||||||
target.Math = object.setPrototype(_Math, Object.prototype);
|
target.Math = object.setPrototype(_Math, Object.prototype);
|
||||||
target.JSON = object.setPrototype(JSON, Object.prototype);
|
target.JSON = object.setPrototype(JSON, Object.prototype);
|
||||||
|
|
||||||
|
@ -79,6 +79,8 @@ export interface Primordials {
|
|||||||
compile(src: string): Function;
|
compile(src: string): Function;
|
||||||
setGlobalPrototypes(prototype: Record<string, any>): void;
|
setGlobalPrototypes(prototype: Record<string, any>): void;
|
||||||
now(): number;
|
now(): number;
|
||||||
|
next(func: () => void): void;
|
||||||
|
schedule(func: () => void, delay: number): () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.undefined = void 0;
|
globalThis.undefined = void 0;
|
||||||
@ -97,6 +99,8 @@ export const {
|
|||||||
setGlobalPrototypes,
|
setGlobalPrototypes,
|
||||||
compile,
|
compile,
|
||||||
now,
|
now,
|
||||||
|
next,
|
||||||
|
schedule,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
export type regex = InstanceType<typeof regex>;
|
export type regex = InstanceType<typeof regex>;
|
154
src/lib/libs/promise.ts
Normal file
154
src/lib/libs/promise.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import { func, next, object, symbol } from "./primordials.ts";
|
||||||
|
|
||||||
|
enum PromiseState {
|
||||||
|
Pending = "pend",
|
||||||
|
Fulfilled = "ful",
|
||||||
|
Rejected = "rej",
|
||||||
|
}
|
||||||
|
|
||||||
|
const pState: unique symbol = symbol.makeSymbol("Promise.state") as any;
|
||||||
|
const pValue: unique symbol = symbol.makeSymbol("Promise.value") as any;
|
||||||
|
const pFulHandles: unique symbol = symbol.makeSymbol("Promise.fulfillHandles") as any;
|
||||||
|
const pRejHandles: unique symbol = symbol.makeSymbol("Promise.rejectHandles") as any;
|
||||||
|
|
||||||
|
function makePromise<T>(): Promise<T> {
|
||||||
|
return object.setPrototype({
|
||||||
|
[pState]: PromiseState.Pending,
|
||||||
|
[pFulHandles]: [],
|
||||||
|
[pRejHandles]: [],
|
||||||
|
}, Promise.prototype) as Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fulfill(self: Promise<any>, val: any) {
|
||||||
|
if (self[pState] !== PromiseState.Pending) return;
|
||||||
|
if (self === val) throw new Error("A promise may not be fulfilled with itself");
|
||||||
|
|
||||||
|
if (val != null && typeof val.then === "function") {
|
||||||
|
val.then(
|
||||||
|
(val: any) => fulfill(self, val),
|
||||||
|
(err: any) => reject(self, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self[pValue] = val;
|
||||||
|
self[pState] = PromiseState.Fulfilled;
|
||||||
|
|
||||||
|
const handles = self[pFulHandles]!;
|
||||||
|
|
||||||
|
for (let i = 0; i < handles.length; i++) {
|
||||||
|
handles[i](val);
|
||||||
|
}
|
||||||
|
|
||||||
|
self[pFulHandles] = undefined;
|
||||||
|
self[pRejHandles] = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function reject(self: Promise<any>, val: any) {
|
||||||
|
if (self[pState] !== PromiseState.Pending) return;
|
||||||
|
if (self === val) throw new Error("A promise may not be rejected with itself");
|
||||||
|
|
||||||
|
if (val != null && typeof val.then === "function") {
|
||||||
|
val.then(
|
||||||
|
(val: any) => reject(self, val),
|
||||||
|
(err: any) => reject(self, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self[pValue] = val;
|
||||||
|
self[pState] = PromiseState.Rejected;
|
||||||
|
|
||||||
|
const handles = self[pRejHandles]!;
|
||||||
|
|
||||||
|
for (let i = 0; i < handles.length; i++) {
|
||||||
|
handles[i](val);
|
||||||
|
}
|
||||||
|
|
||||||
|
self[pFulHandles] = undefined;
|
||||||
|
self[pRejHandles] = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handle<T>(self: Promise<T>, ful?: (val: T) => void, rej?: (err: any) => void) {
|
||||||
|
if (self[pState] === PromiseState.Pending) {
|
||||||
|
if (ful != null) {
|
||||||
|
self[pFulHandles]![self[pFulHandles]!.length] = ful;
|
||||||
|
}
|
||||||
|
if (rej != null) {
|
||||||
|
self[pRejHandles]![self[pRejHandles]!.length] = rej;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (self[pState] === PromiseState.Fulfilled) {
|
||||||
|
if (ful != null) ful(self[pValue] as T);
|
||||||
|
}
|
||||||
|
else if (self[pState] === PromiseState.Rejected) {
|
||||||
|
if (rej != null) rej(self[pValue]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Promise<T> {
|
||||||
|
public [pState]: PromiseState;
|
||||||
|
public [pValue]?: T | unknown;
|
||||||
|
public [pFulHandles]?: ((val: T) => void)[] = [];
|
||||||
|
public [pRejHandles]?: ((val: T) => void)[] = [];
|
||||||
|
|
||||||
|
public then<Res>(ful?: (val: T) => Res, rej?: (err: any) => Res) {
|
||||||
|
if (typeof ful !== "function") ful = undefined;
|
||||||
|
if (typeof rej !== "function") rej = undefined;
|
||||||
|
|
||||||
|
const promise = makePromise<Res>();
|
||||||
|
|
||||||
|
handle(this,
|
||||||
|
val => next(() => {
|
||||||
|
if (ful == null) fulfill(promise, val);
|
||||||
|
else {
|
||||||
|
try { fulfill(promise, ful(val)); }
|
||||||
|
catch (e) { reject(promise, e); }
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
err => next(() => {
|
||||||
|
if (rej == null) reject(promise, err);
|
||||||
|
else {
|
||||||
|
try { fulfill(promise, rej(err)); }
|
||||||
|
catch (e) { reject(promise, e); }
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
public catch<Res>(rej?: (err: any) => Res) {
|
||||||
|
return this.then(undefined, rej);
|
||||||
|
}
|
||||||
|
public finally(fn?: () => void) {
|
||||||
|
if (typeof fn !== "function") return this["then"]();
|
||||||
|
|
||||||
|
return this.then(
|
||||||
|
v => {
|
||||||
|
fn();
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
v => {
|
||||||
|
fn();
|
||||||
|
throw v;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(fn: (fulfil: (val: T) => void, reject: (err: unknown) => void) => void) {
|
||||||
|
this[pState] = PromiseState.Pending;
|
||||||
|
|
||||||
|
fn(val => fulfill(this, val), err => reject(this, err));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static resolve(val: any) {
|
||||||
|
const res = makePromise();
|
||||||
|
fulfill(res, val);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
public static reject(val: any) {
|
||||||
|
const res = makePromise();
|
||||||
|
reject(res, val);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func.setCallable(Promise, false);
|
24
src/main/resources/lib/async.d.ts
vendored
Normal file
24
src/main/resources/lib/async.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
declare type Timer = number;
|
||||||
|
|
||||||
|
declare function setTimeout(func: () => void, time: number): Timer;
|
||||||
|
declare function setTimer(func: () => void, time: number): Timer;
|
||||||
|
declare function setImmediate(func: () => void): void;
|
||||||
|
|
||||||
|
declare function clearTimeout(timer: Timer): void;
|
||||||
|
declare function clearTimer(timer: Timer): void;
|
||||||
|
|
||||||
|
declare type Awaited<T> = T extends { then(fn?: (val: infer Res) => void) } ? Awaited<Res> : T;
|
||||||
|
|
||||||
|
declare interface Thenable<T> {
|
||||||
|
then<Res = T, Rej = never>(onFulfill?: (val: T) => Res, onReject?: (err: any) => Rej): Promise<Res | Rej>;
|
||||||
|
}
|
||||||
|
declare interface Promise<T> extends Thenable<T> {
|
||||||
|
catch<Res = T>(onReject?: (err: any) => Res): Promise<Res>;
|
||||||
|
finally(fn?: () => void): Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface PromiseConstructor {
|
||||||
|
new <T>(fn: (res: (val: T) => void, rej: (err: any) => void) => void): Promise<T>;
|
||||||
|
resolve<T>(val: T): Promise<Awaited<T>>;
|
||||||
|
reject<T>(err: unknown): Promise<T>;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user