Skip to content

Instantly share code, notes, and snippets.

@nowelium
Created January 13, 2012 03:05
Show Gist options
  • Save nowelium/1604371 to your computer and use it in GitHub Desktop.
Save nowelium/1604371 to your computer and use it in GitHub Desktop.
CountdownLatch
var CountdownLatch = function (limit){
this.limit = limit;
this.count = 0;
this.waitBlock = function (){};
};
CountdownLatch.prototype.countDown = function (){
this.count = this.count + 1;
if(this.limit <= this.count){
return this.waitBlock();
}
};
CountdownLatch.prototype.await = function(callback){
this.waitBlock = callback;
};
var barrier = new CountdownLatch(2);
setTimeout(function (){
console.log('work A');
barrier.countDown();
}, 100);
setTimeout(function (){
console.log('work B');
barrier.countDown();
}, 200);
console.log('wait for all to finish...');
barrier.await(function(){
console.log('done all');
});
==>
wait for all to finish...
work A
work B
done all
@velickym
Copy link

velickym commented May 2, 2015

Respect man - nice, simple and extremely handy. Thanks.

@dhirajforyou
Copy link

Yes, Simple and excellent work.

@sukima
Copy link

sukima commented Sep 5, 2016

You could make this API even better with an async function:

var CountdownLatch = function (limit){
  this.limit = limit;
  this.count = 0;
  this.waitBlock = function (){};
};
CountdownLatch.prototype.async = function (fn){
  var _this = this;
  fn(function (){
    _this.count = _this.count + 1;
    if(_this.limit <= _this.count){
      return _this.waitBlock();
    }
  });
};
CountdownLatch.prototype.await = function(callback){
  this.waitBlock = callback;
};
var barrier = new CountdownLatch(2);

barrier.async(function (done){
  setTimeout(function (){
    console.log('work A');
    done();
  }, 100);
});
barrier.async(function (done){
  setTimeout(function (){
    console.log('work B');
    done();
  }, 200);
});
console.log('wait for all to finish...');
barrier.await(function(){
  console.log('done all');
});
==>
wait for all to finish...
work A
work B
done all

JSBin example

@herrgrossmann
Copy link

I have created a CountDownLatch with typescript using a Promise:

/**
 * Utility class inspired by the Java implementation of the CountDownLatch
 */
export class CountDownLatch {

	private readonly promise: Promise<void>;

	private countDownFunction: () => number;
	private count: number;

	/**
	 * Creates a new instance with a given count
	 *
	 * @param count The initial count
	 */
	constructor(count: number) {
		this.count = Math.max(count, 0);
		this.promise = new Promise<void>(resolve => {
			this.countDownFunction = () => {
				if (this.count > 0) {
					this.count = this.count - 1;
					if (this.count <= 0) {
						resolve();
					}
				}
				return this.count;
			};

			//Resolve promise if initial value is less or equal 0
			//Maybe count was calculated from data or something else
			//so this case makes sense under some circumstances
			if (count <= 0) {
				resolve();
			}
		});
	}

	/**
	 * Decrement the count by one
	 */
	public countDown(): number {
		return this.countDownFunction();
	}

	/**
	 * Get's the current count value of the latch
	 */
	public getCount(): number {
		return this.count;
	}

	/**
	 * Await until the count reaches zero (0)
	 */
	public async awaitZero() {
		await this.promise;
	}

	/**
	 * Get's the promise that will be resolve after count reached zero
	 */
	public getPromise() {
		return this.promise;
	}
}

Here is a test case that shows how it works:

it('Test count down latch with two workers', async () => {
		const latch = new CountDownLatch(2);

		let counter = 0;

		setTimeout(() => {
			counter++;
			latch.countDown();
		}, 200);

		setTimeout(() => {
			counter++;
			latch.countDown();
		}, 200);

		await latch.awaitZero();

		expect(counter).toEqual(2);
	});

@Umaaz
Copy link

Umaaz commented Apr 9, 2021

👍 Thanks saved me having to make one!

@noamtamim
Copy link

@herrgrossmann this is great, thanks! Maybe publish to NPM?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment