Socket
Socket
Sign inDemoInstall

async-mutex

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-mutex - npm Package Compare versions

Comparing version 0.1.4 to 0.2.0

es6/index.js

31

CHANGELOG.md
# Changelog
## 0.1.0
## 0.2.0
* Initial release
* Add a `Semaphore`, reimplement `Mutex` on top of it
* Add a `withTimeout` decorator that limits the time the program waits
for the mutex or semaphore to become available
* Support native ES6 imports on Node >= 12
* Provide an ES6 module entrypoint for ES6 aware bundlers
* Dependency bump
* Switch from TSlint to ESlint
* Enable code coverage in tests
## 0.1.1
## 0.1.4
* Fix documentation for `acquire`
* Documentation updates (thanks to hmil and 0xflotus)
* Update build dependencies
## 0.1.3
* Move deps to devDependencies (thanks to Meirion Hughes for the PR)
* Upgrade deps
## 0.1.2

@@ -18,10 +31,8 @@

## 0.1.3
## 0.1.1
* Move deps to devDependencies (thanks to Meirion Hughes for the PR)
* Upgrade deps
* Fix documentation for `acquire`
## 0.1.4
## 0.1.0
* Documentation updates (thanks to hmil and 0xflotus)
* Update build dependencies
* Initial release
export { default as Mutex } from './Mutex';
export { default as MutexInterface } from './MutexInterface';
export { default as Semaphore } from './Semaphore';
export { default as SemaphoreInterface } from './SemaphoreInterface';
export { withTimeout } from './withTimeout';

@@ -5,1 +5,6 @@ "use strict";

exports.Mutex = Mutex_1.default;
var Semaphore_1 = require("./Semaphore");
exports.Semaphore = Semaphore_1.default;
var withTimeout_1 = require("./withTimeout");
exports.withTimeout = withTimeout_1.withTimeout;
//# sourceMappingURL=index.js.map
import MutexInterface from './MutexInterface';
declare class Mutex implements MutexInterface {
isLocked(): boolean;
acquire(): Promise<MutexInterface.Releaser>;
runExclusive<T>(callback: MutexInterface.Worker<T>): Promise<T>;
private _dispatchNext;
private _queue;
private _pending;
isLocked(): boolean;
private _semaphore;
}
export default Mutex;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var Semaphore_1 = require("./Semaphore");
var Mutex = /** @class */ (function () {
function Mutex() {
this._queue = [];
this._pending = false;
this._semaphore = new Semaphore_1.default(1);
}
Mutex.prototype.isLocked = function () {
return this._pending;
};
Mutex.prototype.acquire = function () {
var _this = this;
var ticket = new Promise(function (resolve) { return _this._queue.push(resolve); });
if (!this._pending) {
this._dispatchNext();
}
return ticket;
};
Mutex.prototype.runExclusive = function (callback) {
return this
.acquire()
.then(function (release) {
var result;
try {
result = callback();
}
catch (e) {
release();
throw (e);
}
return Promise
.resolve(result)
.then(function (x) { return (release(), x); }, function (e) {
release();
throw e;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, releaser;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this._semaphore.acquire()];
case 1:
_a = _b.sent(), releaser = _a[1];
return [2 /*return*/, releaser];
}
});
});
};
Mutex.prototype._dispatchNext = function () {
if (this._queue.length > 0) {
this._pending = true;
this._queue.shift()(this._dispatchNext.bind(this));
}
else {
this._pending = false;
}
Mutex.prototype.runExclusive = function (callback) {
return this._semaphore.runExclusive(function () { return callback(); });
};
Mutex.prototype.isLocked = function () {
return this._semaphore.isLocked();
};
return Mutex;
}());
exports.default = Mutex;
//# sourceMappingURL=Mutex.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=MutexInterface.js.map
{
"name": "async-mutex",
"version": "0.1.4",
"version": "0.2.0",
"description": "A mutex for guarding async workflows",
"scripts": {
"prepublish": "tslint src/**/*.ts test/**/*.ts && tsc",
"pretest": "tslint src/**/*.ts test/**/*.ts && tsc -p tsconfig.test.json",
"test": "mocha -R spec -u tdd build/test"
"lint": "eslint src/**/*.ts test/**/*.ts",
"build": "tsc && tsc -p tsconfig.es6.json && tsc -p tsconfig.mjs.json && rollup -o index.mjs mjs/index.js",
"prepublish": "yarn test && yarn build",
"test": "yarn lint && nyc --reporter=text --reporter=html --reporter=lcov mocha test/*.ts",
"coveralls": "cat ./coverage/lcov.info | coveralls"
},

@@ -16,2 +18,31 @@ "author": "Christian Speckner <cnspeckn@googlemail.com> (https://github.com/DirtyHairy/)",

},
"prettier": {
"printWidth": 120,
"tabWidth": 4,
"singleQuote": true,
"parser": "typescript"
},
"importSort": {
".js, .jsx, .ts, .tsx": {
"style": "eslint",
"parser": "typescript"
}
},
"eslintConfig": {
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"eqeqeq": "error",
"@typescript-eslint/no-namespace": "off",
"no-async-promise-executor": "off"
}
},
"keywords": [

@@ -22,14 +53,34 @@ "mutex",

"files": [
"lib"
"lib",
"es6",
"index.mjs"
],
"devDependencies": {
"@types/mocha": "^5.2.7",
"@types/node": "^12.7.8",
"mocha": "^6.2.0",
"tslint": "^5.20.0",
"@sinonjs/fake-timers": "^6.0.1",
"@types/mocha": "^7.0.2",
"@types/node": "^13.11.0",
"@types/sinonjs__fake-timers": "^6.0.1",
"@typescript-eslint/eslint-plugin": "^2.26.0",
"@typescript-eslint/parser": "^2.26.0",
"coveralls": "^3.0.11",
"eslint": "^6.8.0",
"import-sort-style-eslint": "^6.0.0",
"mocha": "^7.1.1",
"nyc": "^15.0.1",
"prettier": "^2.0.2",
"prettier-plugin-import-sort": "^0.0.4",
"rollup": "^2.3.2",
"ts-node": "^8.8.1",
"typescript": "^3.6.3"
},
"main": "lib/index.js",
"module": "es6/index.js",
"types": "lib/index.d.ts",
"dependencies": {}
"exports": {
"import": "./index.mjs",
"require": "./lib/index.js"
},
"dependencies": {
"tslib": "^1.11.1"
}
}
[![Build Status](https://travis-ci.org/DirtyHairy/async-mutex.svg?branch=master)](https://travis-ci.org/DirtyHairy/async-mutex)
[![npm version](https://badge.fury.io/js/async-mutex.svg)](https://badge.fury.io/js/async-mutex)
[![Coverage Status](https://coveralls.io/repos/github/DirtyHairy/async-mutex/badge.svg?branch=master)](https://coveralls.io/github/DirtyHairy/async-mutex?branch=master)
# What is it?
This package implements a mutex for synchronizing asynchronous operations in
This package implements primitives for synchronizing asynchronous operations in
Javascript.
## Mutex
The term "mutex" usually refers to a data structure used to synchronize

@@ -27,7 +30,27 @@ concurrent processes running on different threads. For example, before accessing

This library solves the problem by applying the concept of mutexes to Javascript.
A mutex is locked by providing a worker callback that will be called once no other locks
are held on the mutex. Once the async process is complete (usually taking multiple
spins of the event loop), a callback supplied to the worker is called in order
Locking the mutex will return a promise that resolves once the mutex becomes
available. Once the async process is complete (usually taking multiple
spins of the event loop), a callback supplied to the caller is called in order
to release the mutex, allowing the next scheduled worker to execute.
# Semaphore
Imagine a situation where you need to control access to several instances of
a shared resource. For example, you might want to distribute images between several
worker processes that perform transformations, or you might want to create a web
crawler that performs a defined number of requests in parallel.
A semaphore is a data structure that is initialized to a positive integer value and that
can be locked multiple times.
As long as the semaphore value is positive, locking it will return the current value
and the locking process will continue execution immediatelly; the semaphore will
be decremented upon locking. Releasing the lock will increment the semaphore again.
Once the semaphore has reached zero, the next process that attempts to acquire a lock
will be suspended until another process releases its lock and this increments the semaphore
again.
This library provides a semaphore implementation for Javascript that is similar to the
mutex implementation described above.
# How to use it?

@@ -42,3 +65,3 @@

The library is written in TypeScript and will work in any environment that
supports ES5 and ES6 promises. If ES6 promises are not supported natively,
supports ES5, ES6 promises and `Array.isArray`. On ancient browsers,
a shim can be used (e.g. [core-js](https://github.com/zloirock/core-js)).

@@ -48,24 +71,29 @@ No external typings are required for using this library with

Starting with Node 12, native ES6 style imports are supported.
## Importing
ES5 / CommonJS
**CommonJS:**
```javascript
var asyncMutex = require('async-mutex').Mutex;
var Mutex = require('async-mutex').Mutex;
var Semaphore = require('async-mutex').Semaphore;
var withTimeout = require('async-mutex').withTimeout;
```
ES6
**ES6:**
```javascript
import {Mutex} from 'async-mutex';
import {Mutex, Semaphore, withTimeout} from 'async-mutex';
```
TypeScript
Starting with Node 12, native ES6 style imports are supported.
**TypeScript:**
```typescript
import {Mutex, MutexInterface} from 'async-mutex';
import {Mutex, MutexInterface, Semaphore, SemaphoreInterface, withTimeout} from 'async-mutex';
```
## API
## Mutex API
### Creating
ES5/ES6/TypeScript
```typescript

@@ -79,3 +107,3 @@ const mutex = new Mutex();

ES5/ES6/TypeScript
Promise style:
```typescript

@@ -89,12 +117,3 @@ mutex

`acquire` returns an (ES6) promise that will resolve as soon as the mutex is
available and ready to be accessed. The promise resolves with a function `release` that
must be called once the mutex should be released again.
**IMPORTANT:** Failure to call `release` will hold the mutex locked and will
lilely deadlock the application. Make sure to call `release` under all circumstances
and handle exceptions accordingly.
##### Async function example (ESnext/TypeScript)
async/await:
```typescript

@@ -110,5 +129,13 @@ const release = await mutex.acquire();

`acquire` returns an (ES6) promise that will resolve as soon as the mutex is
available and ready to be accessed. The promise resolves with a function `release` that
must be called once the mutex should be released again.
**IMPORTANT:** Failure to call `release` will hold the mutex locked and will
lilely deadlock the application. Make sure to call `release` under all circumstances
and handle exceptions accordingly.
### Synchronized code execution
ES5/ES6/TypeScript
Promise style:
```typescript

@@ -124,11 +151,6 @@ mutex

##### Async function example (ESnext/TypeScript)
This example is equivalent to the `async`/`await` example that
locks the mutex directly:
async/await:
```typescript
await mutex.runExclusive(async () => {
const i = await store.get();
await store.put(i + 1);
// ...
});

@@ -138,5 +160,5 @@ ```

`runExclusive` schedules the supplied callback to be run once the mutex is unlocked.
The function is expected to return a [Promises/A+](https://promisesaplus.com/)
compliant promise. Once the promise is resolved (or rejected), the mutex is released.
`runExclusive` returns a promise that adopts the state of the function result.
The function may return a promise. Once the promise is resolved or rejected (or immediatelly after
execution if an immediate value was returned),
the mutex is released. `runExclusive` returns a promise that adopts the state of the function result.

@@ -148,3 +170,2 @@ The mutex is released and the result rejected if an exception occurs during execution

ES5/ES6/TypeScript
```typescript

@@ -154,4 +175,105 @@ mutex.isLocked();

## Semaphore API
### Creating
```typescript
const semaphore = new Semaphore(initialValue);
```
Creates a new semaphore. `initialValue` is a positive integer that defines the
initial value of the semaphore (aka the maximum number of concurrent consumers)
### Locking
Promise style:
```typescript
semaphore
.acquire()
.then(function([value, release]) {
// ...
});
```
async/await:
```typescript
const [value, release] = await semaphore.acquire();
try {
// ...
} finally {
release();
}
```
`acquire` returns an (ES6) promise that will resolve as soon as the semaphore is
available and ready to be accessed. The promise resolves to an array with the
first entry being the current value of the semaphore, and the second value a
function that must be called to release the semaphore once the critical operation
has completed.
**IMPORTANT:** Failure to call `release` will hold the semaphore locked and will
lilely deadlock the application. Make sure to call `release` under all circumstances
and handle exceptions accordingly.
### Synchronized code execution
Promise style:
```typescript
semaphore
.runExclusive(function(value) {
// ...
})
.then(function(result) {
// ...
});
```
async/await:
```typescript
await semaphore.runExclusive(async (value) => {
// ...
});
```
`runExclusive` schedules the supplied callback to be run once the semaphore is available.
The callback will receive the current value of the semaphore as its argument.
The function may return a promise. Once the promise is resolved or rejected (or immediatelly after
execution if an immediate value was returned),
the semaphore is released. `runExclusive` returns a promise that adopts the state of the function result.
The semaphore is released and the result rejected if an exception occurs during execution
if the callback.
### Checking whether the semaphore is locked
```typescript
semaphore.isLocked();
```
The semaphore is considered to be locked if it has a value of zero.
## Limiting the time waiting for a mutex or semaphore to become available
Sometimes it is desirable to limit the time a program waits for a mutex or
semaphore to become available. The `withTimeout` decorator can be applied
to both semaphores and mutexes and changes the behavior of `acquire` and
`runExclusive` accordingly.
```typescript
const mutexWithTimeout = withTimeout(new Mutex(), 100, new Error('timeout'));
const semaphoreWithTimeout = withTimeout(new Semaphore(5), 100, new Error('timeout'));
```
The API of the decorated mutex or semaphore is unchanged.
The second argument of `withTimeout` is
the timout in milliseconds. After the timeout is exceeded, the promsie returned by
`acquire` and `runExclusive` will reject. The latter will not run the provided callback in
case of an timeout.
The third argument of `withTimeout` is optional and can be used to
customize the error with which the promise is rejected.
# License
Feel free to use this library under the conditions of the MIT license.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc