This is an abstract resource pool utility library based on the resource pool pattern, JavaScript, and TypeScript friendly. It helps you quickly build a resource pool and manage it.
Supports the following features:
- Creating a resource pool
- Acquiring and releasing resources
- Scaling up and down the resource pool
- Listening to resource pool events
- Listening to resource events
- Asynchronous scheduling of resources
npm install @cat5th/pool.js
or yarn
yarn add @cat5th/pool.js
Build a resource pool
import { Pool } from '@cat5th/pool.js';
const pool = new Pool(3);
Build a Web Worker resource pool
import { Pool } from '@cat5th/pool.js';
const workerPool = new Pool((created) => {
if (created > 3) {
return undefined;
}
const worker = new Worker('worker.js');
return worker;
});
const limiter = workerPool.limit();
limiter(function() {
// this === worker
this.postMessage('hello');
});
Limit the request rate to a maximum of 10 times per second.
import { limit } from '@cat5th/pool.js';
const request = limit(function() {
const response = await fetch('https://api.github.com');
return response.json();
}, 10, {
minDuration: 1000,
});
for (let i = 0; i < 100; i++) {
request();
}
Please see example
import { Pool } from '@cat5th/pool.js';
const create = (created) => {
// create resource
return {
// `created` is the number of resources created
id: created,
};
};
const pool = new Pool(create);
// Or pass in an object
const pool = new Pool({
create,
// The initial number of resources to create
initialSize: 10,
// Resource reset function
reset: (resource) => {
console.log('The resource has been released');
},
});
// Or pass in a number
const pool = new Pool(10);
// equivalent to
const pool = new Pool((created) => {
return created > 10 ? undefined : Object.create(null);
});
// Synconous acquire
const resource = pool.acquire();
// resource?.id === 0
// When the resource pool is empty, `acquire` returns `undefined`
// Asynchronous acquire
const resource = await pool.acquire(true);
// resource.id === 0
// When the resource pool is empty, will wait for the resource to be released
// Asynchronous acquire can be aborted by passing in an `AbortSignal`
const controller = new AbortController();
const resource = await pool.acquire(true, controller.signal);
controller.abort();
// Error will be thrown
resource.id === 0
// Release is asynchronous
pool.release(resource);
// Listen to the `acquire` event
pool.on('acquire', (resource) => {
console.log(`Resource ${resource.id} has been acquired`);
});
// Listen to the `release` event
pool.on('release', (resource) => {
console.log(`Resource ${resource.id} has been released`);
});
Pool implements the Iterable
interface, you can use for...of
to iterate.
At the same time, Pool
also implements the AsyncIterable
interface, you can use for await...of
to iterate asynchronously.
// Iterate over the resources in the resource pool, and get the resources at the same time,
// When iterating synchronously, if there are no resources in the resource pool, the iteration will exit
for (const resource of pool) {
console.log(resource.id);
}
// When iterating asynchronously, if there are no resources in the resource pool, it will wait for the resources to be acquired
// So when iterating asynchronously, it will not exit the iteration, which is equivalent to an infinite loop
for await (const resource of pool) {
console.log(resource.id);
}
Pool implements the PromiseLike
interface, you can use await
to wait.
// await pool means waiting for all resources to be released before returning
await pool;
const limiter = pool.limit();
// Resource limiter is an execution function that needs to pass in an asynchronous consumption function and its parameters
// The limiter returns a `Promise`, which will execute the consumption function when there are resources in the resource pool
// When there are no resources in the resource pool, the consumption function will be executed when there are resources in the resource pool
const result = await limiter(async function(...args) {
console.log(`Current resource is ${this.id}`)
// resource.id === 0
// args === [1, 2, 3]
return 1;
}, 1, 2, 3);
// limiter method supports passing in limiter options
const limiter = pool.limit({
// The minimum execution time of the consumption function, if the execution time of the consumption function is less than `minDuration`,
// The execution will end at the same time as the consumption function, but the used resources will be released after `minDuration`
minDuration: 1000,
});
// limiter has a `abort` method that can abort the current consumption function, the return of execution will throw an error
limiter.abort(new DOMException('AbortError'));
Yes, cat5th/pool.js
provides a convenient method called pLimit
and Pool.limit
, which is an alias for Pool.prototype.limit
.
import { pLimit } from '@cat5th/pool.js';
// The first argument of `pLimit` is the parameter for the `Pool` constructor, and the second argument is the parameter for `Pool.prototype.limit`
const limiter = pLimit(10, {
minDuration: 1000,
});
limit
is a wrapper method for Pool.limit
, which is directly return a function that can be executed.
import { limit } from '@cat5th/pool.js';
const fn = limit(async function() {
// ...
}, 10, {
minDuration: 1000,
});
fn(...args);
Inspired by the following projects: