Skip to content

Commit

Permalink
feat(promise): add withResolvers method (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
mg901 authored Oct 8, 2024
1 parent 18ddf77 commit b4bab4c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 14 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ module.exports = {
'import/no-extraneous-dependencies': 0,

'@typescript-eslint/no-use-before-define': 0,
eqeqeq: [2, 'smart'],
'newline-before-return': 2,
'no-console': 2,
'@typescript-eslint/no-unused-vars': [
2,
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
},
};
Binary file modified bun.lockb
Binary file not shown.
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/config-conventional": "^19.5.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^11.1.0",
"@semantic-release/git": "^10.0.1",
Expand All @@ -26,25 +26,25 @@
"@types/lodash.isfunction": "^3.0.9",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitest/coverage-istanbul": "^2.0.4",
"bun-types": "^1.1.21",
"@vitest/coverage-istanbul": "^2.1.1",
"bun-types": "^1.1.27",
"commitizen": "^4.3.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.2.1",
"git-cz": "^4.9.0",
"husky": "^8.0.3",
"lint-staged": "^15.2.7",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"rimraf": "^5.0.9",
"semantic-release": "^24.0.0",
"type-fest": "^4.23.0",
"rimraf": "^5.0.10",
"semantic-release": "^24.1.1",
"type-fest": "^4.26.1",
"typescript": "^5.0.0",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.0.4"
"vitest": "^2.1.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
Expand Down
2 changes: 1 addition & 1 deletion src/data-structures/cache/lru/lru-cache-on-map/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class LRUCache<Key extends keyof any, Value = any>

#evictLeastRecentItem() {
const firstKey = this.#storage.keys().next().value;
this.#storage.delete(firstKey);
this.#storage.delete(firstKey!);
}

get(key: Key): Value | null {
Expand Down
39 changes: 36 additions & 3 deletions src/data-structures/promise/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Promises/A+ spec
// https://github.com/promises-aplus/promises-spec

import { Queue } from '@/data-structures/queue';
import isFunction from 'lodash.isfunction';
import { ValueOf } from 'type-fest';
Expand Down Expand Up @@ -194,12 +197,40 @@ export class MyPromise<T = any> implements IMyPromise<T> {
return MyPromise.all<PromiseSettledResult<Awaited<T>>>(items);
}

static withResolvers<T>() {
let resolve!: (value: T | PromiseLike<T>) => void;
let reject!: (reason?: any) => void;

const promise = new MyPromise<T>((res, rej) => {
resolve = res;
reject = rej;
});

return {
promise,
resolve,
reject,
};
}

constructor(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void,
) => void,
) {
if (new.target === undefined) {
throw new TypeError(
`${this.constructor.name} constructor cannot be invoked without 'new'`,
);
}

if (typeof executor !== 'function') {
throw new TypeError(
`${this.constructor.name} resolver ${typeof executor} is not a function`,
);
}

try {
executor(this.#resolve.bind(this), this.#reject.bind(this));
} catch (error) {
Expand Down Expand Up @@ -245,7 +276,9 @@ export class MyPromise<T = any> implements IMyPromise<T> {
const result = handler(this.#value as T);

if (isThenable(result)) {
result.then(resolve, reject);
queueMicrotask(() => {
result.then(resolve, reject);
});
} else {
resolve(result);
}
Expand Down Expand Up @@ -307,7 +340,7 @@ export class MyPromise<T = any> implements IMyPromise<T> {

// eslint-disable-next-line class-methods-use-this
get [Symbol.toStringTag]() {
return 'MyPromise';
return `${this.constructor.name}`;
}
}

Expand All @@ -326,7 +359,7 @@ function handleNonIterable(it: any): void {
);
}

function isThenable(it: any): it is PromiseLike<unknown> {
function isThenable(it: any): it is PromiseLike<any> {
return !!(it && isFunction(it.then));
}

Expand Down

0 comments on commit b4bab4c

Please sign in to comment.