Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz

pids
logs
results

.nyc_output
coverage
node_modules
npm-debug.log

npm-debug.log
22 changes: 15 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
sudo: false
os: linux
language: node_js
node_js:
- "0.12"
- "0.10"
- "0.8"
- "iojs"
- "iojs-v1.0.4"
- "iojs-v2"
- "iojs-v3"
sudo: false
- "0.11"
- "0.12"
- "4"
- "5"
- "6"
env:
matrix:
- TEST_SUITE=unit
matrix:
include:
- node_js: "4"
env: TEST_SUITE=lint
script: npm run $TEST_SUITE
80 changes: 43 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
semaphore.js
============
# semaphore

[![Build Status](https://travis-ci.org/abrkn/semaphore.js.svg?branch=master)](https://travis-ci.org/abrkn/semaphore.js)
[![NPM Package](https://img.shields.io/npm/v/semaphore.svg?style=flat-square)](https://www.npmjs.org/package/semaphore)
[![Build Status](https://img.shields.io/travis/abrkn/semaphore.js.svg?branch=master&style=flat-square)](https://travis-ci.org/abrkn/semaphore.js)

Install:
[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)


## Installation

```
npm install semaphore
```

## Examples

Limit simultaneous access to a resource.

```javascript
// Create
var sem = require('semaphore')(capacity);
const Semaphore = require('semaphore')
const sem = new Semaphore(capacity)

// Take
sem.take(fn[, n=1])
Expand All @@ -20,49 +29,46 @@ sem.take(n, fn)
sem.leave([n])
```


```javascript
// Limit concurrent db access
var sem = require('semaphore')(1);
var server = require('http').createServer(req, res) {
sem.take(function() {
expensive_database_operation(function(err, res) {
sem.leave();

if (err) return res.end("Error");

return res.end(res);
});
});
});
const Semaphore = require('semaphore')
const sem = new Semaphore(1)
const server = require('http').createServer((req, res) => {
sem.take(() => {
expensive_database_operation((err, res) => {
sem.leave()
res.end(err === null ? res : 'error')
})
})
})
```

```javascript
// 2 clients at a time
var sem = require('semaphore')(2);
var server = require('http').createServer(req, res) {
res.write("Then good day, madam!");

sem.take(function() {
res.end("We hope to see you soon for tea.");
sem.leave();
});
});
const Semaphore = require('semaphore')
const sem = new Semaphore(2)
const server = require('http').createServer((req, res) => {
res.write("Then good day, madam!")

sem.take(() => {
res.end("We hope to see you soon for tea.")
sem.leave()
})
})
```

```javascript
// Rate limit
var sem = require('semaphore')(10);
var server = require('http').createServer(req, res) {
sem.take(function() {
res.end(".");
setTimeout(sem.leave, 500)
});
});
const Semaphore = require('semaphore')
const sem = new Semaphore(10)
const server = require('http').createServer((req, res) => {
sem.take(() => {
res.end(".")
setTimeout(() => sem.leave(), 500)
})
})
```

License
===
## License

MIT
29 changes: 16 additions & 13 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
{
"name": "semaphore.js",
"version": "1.0.3",
"homepage": "https://github.com/abrkn/semaphore.js",
"authors": [
"Andreas Brekken <[email protected]>"
],
"description": "Limit simultaneous access to a resource.",
"main": "lib/semaphore.js",
"main": "./index.js",
"moduleType": [
"globals",
"amd",
"node"
],
"keywords": [
"semaphore",
"concurrency"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
"test"
],
"keywords": [
"concurrency",
"semaphore"
],
"authors": [
"Andreas Brekken <[email protected]>"
],
"homepage": "https://github.com/abrkn/semaphore.js",
"repository": {
"type": "git",
"url": "https://github.com/abrkn/semaphore.js.git"
}
}
84 changes: 84 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
;(function (global) {
'use strict'

var nextTick = function (fn) { setTimeout(fn, 0) }
if (typeof process !== 'undefined' && process && typeof process.nextTick === 'function') {
// node.js and the like
nextTick = process.nextTick
}

function checkNumber (n) {
if (typeof n !== 'number' || isNaN(n) || !isFinite(n)) {
throw new TypeError('expected number, got ' + n)
}
if (n % 1 !== 0 || n < 1) {
throw new RangeError('expected positive integer number, got ' + n)
}
}

function checkFunction (f) {
if (typeof f !== 'function') throw new TypeError('expected function, got ' + f)
}

function Semaphore (capacity) {
if (!(this instanceof Semaphore)) return new Semaphore(capacity)

this._capacity = capacity || 1
checkNumber(this._capacity)

this._current = 0
this._queue = []
this._leave = this.leave.bind(this)
}

Semaphore.prototype.take = function () {
var item = {}
if (typeof arguments[0] === 'function') {
item.task = arguments[0]
item.n = arguments[1] || 1
} else {
item.task = arguments[1]
item.n = arguments[0] || 1
}

checkFunction(item.task)
checkNumber(item.n)
if (item.n > this._capacity) {
throw new RangeError('expected number in [1, ' + this._capacity + '], got ' + item.n)
}

if (this._current + item.n > this._capacity) {
this._queue.push(item)
} else {
this._current += item.n
item.task(this._leave)
}
}

Semaphore.prototype.leave = function (n) {
n = n || 1
checkNumber(n)

this._current = Math.max(this._current - n, 0)

if (this._queue.length === 0) return
if (this._current + this._queue[0].n > this._capacity) return

var item = this._queue.shift()
this._current += item.n

var leave = this._leave
nextTick(function () { item.task(leave) })
}

if (typeof exports === 'object') {
// node export
module.exports = Semaphore
} else if (typeof define === 'function' && define.amd) {
// amd export
define(function () { return Semaphore })
} else {
// browser global
global.semaphore = global.Semaphore = Semaphore
}
}(this))
96 changes: 0 additions & 96 deletions lib/semaphore.js

This file was deleted.

5 changes: 0 additions & 5 deletions npm-shrinkwrap.json

This file was deleted.

Loading