Skip to content

Commit

Permalink
feedback fixes - add test cases, update code comments, update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
RaishavHanspal committed Nov 20, 2024
1 parent 686f0d8 commit ecc003d
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 13 deletions.
38 changes: 38 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,44 @@ console.log(queue.sizeBy({priority: 0}));
//=> 1
```

#### .setPriority(id, priority)

Update priority of a known promise function, using the `id` identifier, and a priority value to override existing priority value. The updated value of priority ensures whether to execute this promise function sooner or later.

Function works only when we specify a defined concurrency to change any priorities.

For example, this can be used to make a promise function run earlier.

```js
import PQueue from 'p-queue';

const queue = new PQueue({concurrency: 1});

queue.add(async () => '🦄', {priority: 1});
queue.add(async () => '🦀', {priority: 0, id: '🦀'});
queue.add(async () => '🦄', {priority: 1});
queue.add(async () => '🦄', {priority: 1});

queue.setPriority('🦀', 2);
```
In above case, promise function with '🦀' executes second.

We can also delay a promise function.

```js
import PQueue from 'p-queue';

const queue = new PQueue({concurrency: 1});

queue.add(async () => '🦄', {priority: 1});
queue.add(async () => '🦀', {priority: 1, id: '🦀'});
queue.add(async () => '🦄');
queue.add(async () => '🦄', {priority: 0});

queue.setPriority('🦀', -1);
```
In above case, promise function with '🦀' executes last.

#### .pending

Number of running items (no longer in the queue).
Expand Down
13 changes: 7 additions & 6 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT

readonly #throwOnTimeout: boolean;

/** Use to assign a unique identifier to a promise function, if not explicitly specified */
#idAssigner = 1;
// Use to assign a unique identifier to a promise function, if not explicitly specified
#idAssigner = 1n;

/**
Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already.
Expand Down Expand Up @@ -231,6 +231,9 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
});
}

/**
Update priority of a known promise function, using the `id` identifier, and a priority value to override existing priority value. The updated value of priority ensures whether to execute this promise function sooner or later.
*/
setPriority(id: string, priority: number) {
this.#queue.setPriority(id, priority);
}
Expand All @@ -241,10 +244,8 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
async add<TaskResultType>(function_: Task<TaskResultType>, options: {throwOnTimeout: true} & Exclude<EnqueueOptionsType, 'throwOnTimeout'>): Promise<TaskResultType>;
async add<TaskResultType>(function_: Task<TaskResultType>, options?: Partial<EnqueueOptionsType>): Promise<TaskResultType | void>;
async add<TaskResultType>(function_: Task<TaskResultType>, options: Partial<EnqueueOptionsType> = {}): Promise<TaskResultType | void> {
// Incase id is not defined
if (options.id === undefined) {
options.id = (this.#idAssigner++).toString();
}
// In case `id` is not defined.
options.id ??= (this.#idAssigner++).toString();

options = {
timeout: this.timeout,
Expand Down
7 changes: 7 additions & 0 deletions source/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ export type QueueAddOptions = {
@default 0
*/
readonly priority?: number;
/**
Unique identifier for the promise function. This can be used to update priority, before it gets executed.
@default '1'
Value of `id` will be assigned using a bigint number assigner which increments for every new promise function with unspecified id
*/
id?: string;
} & TaskOptions & TimeoutOptions;

Expand Down
6 changes: 1 addition & 5 deletions source/priority-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ export default class PriorityQueue implements Queue<RunFunction, PriorityQueueOp
}

const [item] = this.#queue.splice(existingIndex, 1);
if (item === undefined) {
throw new Error('Undefined Item - No promise function of specified id available in the queue.');
}

this.enqueue(item.run, {priority, id});
this.enqueue(item!.run, {priority, id});
}

dequeue(): RunFunction | undefined {
Expand Down
126 changes: 124 additions & 2 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ test('.setPriority() - execute a promise before planned', async t => {
t.deepEqual(result, ['🐌', '🐢', '🦆']);
});

test.failing('.setPriority() - with invalid "id"', async t => {
test('.setPriority() - execute a promise after planned', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 1});
queue.add(async () => {
Expand All @@ -1166,11 +1166,133 @@ test.failing('.setPriority() - with invalid "id"', async t => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.setPriority('🐢', -1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🦆', '🦆', '🦆', '🦆', '🐢']);
});

test('.setPriority() - execute a promise before planned - concurrency 2', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 2});
queue.add(async () => {
await delay(400);
result.push('🐌');
}, {id: '🐌'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.add(async () => {
await delay(400);
result.push('⚡️');
}, {id: '⚡️'});
queue.setPriority('⚡️', 1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🐢', '🦆']);
t.deepEqual(result, ['🐌', '🦆', '⚡️', '🐢']);
});

test('.setPriority() - execute a promise before planned - concurrency 3', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 3});
queue.add(async () => {
await delay(400);
result.push('🐌');
}, {id: '🐌'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.add(async () => {
await delay(400);
result.push('⚡️');
}, {id: '⚡️'});
queue.add(async () => {
await delay(400);
result.push('🦀');
}, {id: '🦀'});
queue.setPriority('🦀', 1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🦆', '🐢', '🦀', '⚡️']);
});

test('.setPriority() - execute a multiple promise before planned, with variable priority', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 2});
queue.add(async () => {
await delay(400);
result.push('🐌');
}, {id: '🐌'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.add(async () => {
await delay(400);
result.push('⚡️');
}, {id: '⚡️'});
queue.add(async () => {
await delay(400);
result.push('🦀');
}, {id: '🦀'});
queue.setPriority('⚡️', 1);
queue.setPriority('🦀', 2);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🦆', '🦀', '⚡️', '🐢']);
});

test('.setPriority() - execute a promise before planned - concurrency 3 and unspecified `id`', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 3});
queue.add(async () => {
await delay(400);
result.push('🐌');
});
queue.add(async () => {
await delay(400);
result.push('🦆');
});
queue.add(async () => {
await delay(400);
result.push('🐢');
});
queue.add(async () => {
await delay(400);
result.push('⚡️');
});
queue.add(async () => {
await delay(400);
result.push('🦀');
});
queue.setPriority('5', 1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🦆', '🐢', '🦀', '⚡️']);
});

0 comments on commit ecc003d

Please sign in to comment.