diff --git a/.travis.yml b/.travis.yml index 1932865..f856803 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: node_js node_js: - - "0.11" + - "0.12" + - "4" + - "5" diff --git a/README.md b/README.md index 95c9ae2..e71ab27 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Chan A [golang](http://golang.org) like channel implementation for JavaScript that -works well with [co](https://github.com/visionmedia/co). +works well with `ES7 async & await` and [co](https://github.com/tj/co).. [![Build Status](https://travis-ci.org/brentburg/chan.png)](https://travis-ci.org/brentburg/chan) [![Code Climate](https://codeclimate.com/github/brentburgoyne/chan.png)](https://codeclimate.com/github/brentburgoyne/chan) @@ -14,6 +14,7 @@ works well with [co](https://github.com/visionmedia/co). - Channels can be closed - API designed to work well with generators and co - Can be used without generators +- API designed to work well with async&await - Channels can be selected similar to Go's select statement ## Installation @@ -37,30 +38,26 @@ typeof ch // -> 'function' ### Sending values to the channel Values are added to the -channel by calling the function with either `(value)` or `(error, value)`. The -return value is a thunk (a function that take a node-style callback as its only -argument). The callback given to the thunk is called once the value is added. +channel by calling the function with either `(value)` or `(error, value)`. +The return value is a Promise. ```js -ch('foo')(function (err) { - if (err) { - // There was an error putting the value on the channel - } else { - // The value was successfully put on the channel - } +ch('foo').then(function () { + // The value was successfully put on the channel +}).catch(function (err) { + // There was an error putting the value on the channel }) ``` ### Receiving values from the channel -Values are removed from the channel by calling it with a node-style callback as -this first argument. When a value is available on the channel the callback is -called with the value or error. In this case the channel itself can also be a -thunk. +Values are taken off the channel by resolving the channel promise repeatedly. ```js -ch(function (err, val) { - // called when there is a value or error on the channel +ch.then(function (val) { + // called when there is a value on the channel +}).catch(function (err) { + // called when there is an error on the channel }) ``` diff --git a/examples/async.js b/examples/async.js index f84b191..3a8fc12 100644 --- a/examples/async.js +++ b/examples/async.js @@ -20,7 +20,7 @@ co(function *() { console.log('Response added to channel for: ' + urls[i]) } ch.close() -})() +}) co(function *() { while (!ch.done()) { @@ -28,4 +28,4 @@ co(function *() { yield chan.timeout(1000) console.log('Channel yielded') } -})() +}) diff --git a/examples/buffered.js b/examples/buffered.js index d7df6b3..62e2b94 100644 --- a/examples/buffered.js +++ b/examples/buffered.js @@ -10,7 +10,7 @@ co(function *() { yield chan.timeout(100) console.log('<-- ' + (yield ch)) } -})() +}) co(function *() { @@ -20,4 +20,4 @@ co(function *() { console.log(n + ' -->') } ch.close() -})() +}) diff --git a/examples/close.js b/examples/close.js index ec711ad..24b0f35 100644 --- a/examples/close.js +++ b/examples/close.js @@ -13,7 +13,7 @@ co(function *() { } } console.log('Done!') -})() +}) co(function *() { var n = 10 @@ -30,4 +30,4 @@ co(function *() { ch.close() } } -})() +}) diff --git a/examples/errors.js b/examples/errors.js index c9697a9..3a0ab4c 100644 --- a/examples/errors.js +++ b/examples/errors.js @@ -7,11 +7,11 @@ var fs = require('fs') co(function *() { var ch = chan() - fs.readFile('something', ch) + fs.readFile(__filename, ch) try { yield ch } catch (err) { console.log('failed: %s', err.message) } -})() +}) diff --git a/examples/interval.js b/examples/interval.js index e079fee..65ec3e3 100644 --- a/examples/interval.js +++ b/examples/interval.js @@ -8,11 +8,11 @@ co(function *() { while (true) { console.log('a: ' + (yield int)) } -})() +}) co(function *() { var int = chan.interval(30) while (true) { console.log('b: ' + (yield int)) } -})() +}) diff --git a/examples/passing.js b/examples/passing.js index cd84e7d..ef6cd54 100644 --- a/examples/passing.js +++ b/examples/passing.js @@ -10,7 +10,7 @@ co(function *() { while ((n = yield ch)) { console.log(n) } -})() +}) co(function *() { var n = 50 @@ -19,4 +19,4 @@ co(function *() { yield chan.timeout(100) ch(n) } -})() +}) diff --git a/examples/requests.js b/examples/requests.js index 4c70f81..72f567e 100644 --- a/examples/requests.js +++ b/examples/requests.js @@ -22,4 +22,4 @@ co(function *() { while ((res = yield ch)) { console.log(res.status) } -})() +}) diff --git a/examples/select.js b/examples/select.js index 06b27fb..d69620a 100644 --- a/examples/select.js +++ b/examples/select.js @@ -37,4 +37,4 @@ co(function *() { } } -})() +}) diff --git a/examples/stream.js b/examples/stream.js index 4d6ed4f..7596bbc 100644 --- a/examples/stream.js +++ b/examples/stream.js @@ -22,4 +22,4 @@ co(function *() { } console.log('Stream ended') -})() +}) diff --git a/examples/timeout.js b/examples/timeout.js index 6360bae..9c8fe7b 100644 --- a/examples/timeout.js +++ b/examples/timeout.js @@ -7,7 +7,7 @@ var co = require('co') co(function *() { var ch = chan() request.get('http://google.com', ch) - + switch (yield chan.select(ch, chan.timeout(1000))) { case ch: console.log('Google loaded.') @@ -15,4 +15,4 @@ co(function *() { default: console.log('Timeout of 1 second reached.') } -})() +}) diff --git a/lib/async.js b/lib/async.js index b64e4e5..74d09f5 100644 --- a/lib/async.js +++ b/lib/async.js @@ -31,14 +31,22 @@ function async(ch, fn/*, args...*/) { if (arguments.length > 2) { val = [].slice.call(arguments, 1) } - ch(err, val)(function (err) { - receiver[err ? 'error' : 'add'](err) + ch(err, val).then(function (val) { + receiver.add(val) + }).catch(function (err) { + receiver.error(err) }) }) fn.apply(context, args) - return function (cb) { - receiver.callback(cb) - } + return new Promise(function (resolve, reject) { + receiver.callback(function (err, val) { + if (err) { + reject(err) + } else { + resolve(val) + } + }) + }) } diff --git a/lib/channel.js b/lib/channel.js index 4998690..ebbc052 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -40,7 +40,7 @@ Channel.lastCalled = null * @param {Function} cb * @api private */ -Channel.prototype.get = function (cb){ +Channel.prototype.get = function (cb) { if (this.done()) { this.callEmpty(cb) } else if (this.items.length > 0 || this.pendingAdds.length > 0) { @@ -96,9 +96,15 @@ Channel.prototype.add = function (val){ this.pendingAdds.push(receiver) } - return function (cb) { - receiver.callback(cb) - } + return new Promise(function (resolve, reject) { + receiver.callback(function (err, val) { + if (err) { + reject(err) + } else { + resolve(val) + } + }) + }) } /** diff --git a/package.json b/package.json index c255406..43ffec8 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,12 @@ }, "homepage": "https://github.com/brentburgoyne/chan", "devDependencies": { - "co": "^3.0.6", + "co": "^4.6.0", "expect.js": "^0.3.1", - "mocha": "^1.20.1", - "should": "^4.0.4", - "sinon": "^1.10.3", - "split": "^0.3.0", - "superagent": "^0.18.0" + "mocha": "^2.3.4", + "should": "^8.0.1", + "sinon": "^1.17.2", + "split": "^1.0.0", + "superagent": "^1.6.1" } } diff --git a/test/async.js b/test/async.js index 0ccf741..1cda678 100644 --- a/test/async.js +++ b/test/async.js @@ -13,16 +13,15 @@ describe('Async helper', function () { var fn beforeEach(function () { - ch = sinon.stub().returns(function (cb) { cb() }) + ch = sinon.stub().returns(Promise.resolve()) fn = sinon.stub().yields(err, val) }) it( 'should return a function with an arity of 1', function () { - var thunk = async(ch, fn) - thunk.should.be.a.Function - thunk.length.should.be.exactly(1) + var promise = async(ch, fn) + promise.should.be.an.instanceOf(Promise) } ) @@ -60,11 +59,11 @@ describe('Async helper', function () { 'should call callback given to returned function', function (done) { var cb = sinon.spy() - async(ch, fn)(cb) - setImmediate(function () { + async(ch, fn).then(cb) + setTimeout(function () { cb.callCount.should.be.exactly(1) done() - }) + }, 100) } ) diff --git a/test/buffered.js b/test/buffered.js index 8f1e8de..9548ffd 100644 --- a/test/buffered.js +++ b/test/buffered.js @@ -11,16 +11,16 @@ describe('A unbuffered channel', function () { function (done) { var ch = chan(0) // unbuffered var cbCalled = false - ch('foo')(function () { + ch('foo').then((function () { cbCalled = true - }) + })) setImmediate(function () { expect(cbCalled).to.not.be.ok() ch(function (err, val) { - setImmediate(function () { + setTimeout(function () { expect(cbCalled).to.be.ok() done() - }) + }, 100) }) }) } @@ -58,14 +58,14 @@ describe('A buffered channel', function () { var called = 0 var added = 0 while (++added <= buffer + 10) { - ch(added)(function (err) { + ch(added).then(function () { called++ }) } - setImmediate(function () { + setTimeout(function () { expect(called).to.be(buffer) done() - }) + }, 100) } ) @@ -79,16 +79,16 @@ describe('A buffered channel', function () { var ch = chan(1) var cbCalled = false ch('foo') - ch('bar')(function () { + ch('bar').then(function () { cbCalled = true }) setImmediate(function () { expect(cbCalled).to.not.be.ok() ch(function (err, val) { - setImmediate(function () { + setTimeout(function () { expect(cbCalled).to.be.ok() done() - }) + }, 100) }) }) } @@ -98,16 +98,11 @@ describe('A buffered channel', function () { 'should call cb with an error when the channel is closed before adding', function (done) { var ch = chan(0) - var cbCalled = false - ch('foo')(function (err) { - cbCalled = true + ch('foo').catch(function (err) { expect(err).to.be.an(Error) - }) - ch.close() - setImmediate(function () { - expect(cbCalled).to.be.ok() done() }) + ch.close() } ) diff --git a/test/close.js b/test/close.js index 40dbcb3..f9d0faf 100644 --- a/test/close.js +++ b/test/close.js @@ -10,7 +10,7 @@ describe('A closed channel', function () { function () { var ch = chan() ch.close() - ch('foo')(function (err) { + ch('foo').catch(function (err) { expect(err).to.be.an(Error) }) }