await-locks
v0.1.0
Published
Some JavaScript concurrency-control / frequency-control utility classes to manage async tasks easily
Downloads
18
Readme
await-locks
Some JavaScript concurrency-control / frequency-control utility classes, inspired by Java, to manage async tasks easily.
Background
Web developers may have the following how-to questions
- fetch numerous resources one by one
- upload a bunch of files with specific num of parallel tasks
- make actual handling of user actions/requests more even in time (distinguish from throttle/debounce which may drop requests)
In Java language, there are concepts below to manage concurrency tasks
- Reentrant Lock
- Semaphore
- Rate Limiter
So this package is trying to port some Java concurrency concepts to JavaScript runtimes for web developers.
Install
npm install await-locks
Usage
This package contains the following classes:
With these classes you may even implement a "Thread Pool Work Queue"-like pattern.
Take Semaphore
as a example
Usage in Browsers
// import {Semaphore} from 'await-locks';
// import {Semaphore} from '/node_modules/await-locks/dist/await-locks.esm.js';
import Semaphore from '/node_modules/await-locks/src/Semaphore.js';
let semaphore = new Semaphore(4);
async function semaphoreClientExample(millis) {
await semaphore.acquire(1); // acquire 1 permit before request
let p = fetch('/api/sleep?millis=' + millis).then((res) => {
if (!res.ok) {
throw new Error('Error ' + res.status);
}
return res.text();
});
p.finally(() => {
semaphore.release(1); // release 1 permit after request finished
});
return p;
}
let promised = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((millis) => semaphoreClientExample(millis));
Promise.allSettled(promised).then((results) => {
console.log(results);
});
Usage in Node.js
import {Semaphore} from 'await-locks';
let semaphore = new Semaphore(4);
let sleepAsync = (millis) => {
return new Promise((resolve) => {
setTimeout(resolve, millis);
});
};
let handlers = {
async sleep(req, res, next) {
let millis = parseInt(req.query.millis) || 1000;
let t0 = performance.now();
await sleepAsync(millis);
res.status(200).type('text/plain').send((performance.now() - t0).toFixed(0)).end();
},
async semaphoreServerExample(req, res, next) {
let millis = parseInt(req.query.millis) || 1000;
let t0 = performance.now();
await semaphore.acquire(1); // acquire 1 permit before handling the request
await sleepAsync(millis);
res.on('finish', () => {
semaphore.release(1); // release 1 permit after response finished
});
res.status(200).type('text/plain').send((performance.now() - t0).toFixed(0)).end();
}
}
import http from 'http';
import express from 'express';
let app = http2Express(express);
app.get('/api/sleep', handlers.sleep);
app.get('/api/sleep-semaphore', handlers.semaphoreServerExample);
let server = http.createServer({}, app);
server.listen(8080, '127.0.0.1', () => {
console.log('server started.\nhttp://127.0.0.1:8080');
});
Examples
See client-side examples, server-side examples and jasmine tests.
Run Examples
Checkout await-locks from github
npm install
npm run start
Open https://127.0.0.1:8443/client/ for client examples, open https://127.0.0.1:8443/api/ for server APIs. You may also use Java/Servlet to implement an equivalent server-side APIs to run client examples.
Run Tests
npm install -g jasmine
npm run test