Skip to content

Commit

Permalink
Fixes #2634 - Comments gate.ts
Browse files Browse the repository at this point in the history
While reading the codebase, I was briefly confused by the gate decorator.
Here, I've added comments to the decorator to make it easier to understand.
I'm hoping these comments will help others dive through the codebase as well 🙂
  • Loading branch information
sadasant committed Apr 14, 2023
1 parent 640d3f6 commit f01c3fb
Showing 1 changed file with 18 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/system/decorators/gate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
import { isPromise } from '../promise';
import { resolveProp } from './resolver';

/**
* A decorator that gates the execution of a method or getter.
* It ensures that the decorated method is executed only once at a time
* by forcing subsequent calls to wait for the previous execution to complete.
*/
export function gate<T extends (...arg: any) => any>(resolver?: (...args: Parameters<T>) => string) {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
// Stores the original method or getter function in fn variable
let fn: Function | undefined;
if (typeof descriptor.value === 'function') {
fn = descriptor.value;
Expand All @@ -12,10 +18,15 @@ export function gate<T extends (...arg: any) => any>(resolver?: (...args: Parame
}
if (fn == null) throw new Error('Not supported');

// Creates a unique gate key
const gateKey = `$gate$${key}`;

// Replaces the descriptor value with a new function
descriptor.value = function (this: any, ...args: any[]) {
// Resolves the gate key using the resolver function
const prop = resolveProp(gateKey, resolver, ...(args as Parameters<T>));

// Checks if a promise has already been created for the method
if (!Object.prototype.hasOwnProperty.call(this, prop)) {
Object.defineProperty(this, prop, {
configurable: false,
Expand All @@ -25,15 +36,21 @@ export function gate<T extends (...arg: any) => any>(resolver?: (...args: Parame
});
}

// If a promise exists, return it
let promise = this[prop];
if (promise === undefined) {
let result;
try {
// Call the original method
result = fn!.apply(this, args);

// If the result is not a promise, return it
if (result == null || !isPromise(result)) {
return result;
}

// If the result is a promise, set up .then and .catch
// handlers to clear the promise on completion
this[prop] = promise = result
.then((r: any) => {
this[prop] = undefined;
Expand All @@ -49,6 +66,7 @@ export function gate<T extends (...arg: any) => any>(resolver?: (...args: Parame
}
}

// Return the ongoing promise
return promise;
};
};
Expand Down

0 comments on commit f01c3fb

Please sign in to comment.