diff --git a/.gitignore b/.gitignore index e8535e2..a4dd2ff 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,7 @@ jspm_packages # vim swap files *.swp + +# vscode +*.code-workspace +.vscode diff --git a/boot.js b/boot.js index 4c21653..991fe8f 100644 --- a/boot.js +++ b/boot.js @@ -96,6 +96,7 @@ function Boot (server, opts, done) { this._server = server this._current = [] this._error = null + this._isOnCloseHandlerKey = Symbol('isOnCloseHandler') this.setMaxListeners(0) @@ -121,7 +122,6 @@ function Boot (server, opts, done) { // nooping this, we want to emit start only once this._closeQ.drain = noop } - this._thereIsCloseCb = false this._doStart = null const main = new Plugin(this, (s, opts, done) => { @@ -210,6 +210,9 @@ Boot.prototype.after = function (func) { } Boot.prototype.onClose = function (func) { + // this is used to distinguish between onClose and close handlers + // because they share the same queue but must be called with different signatures + func[this._isOnCloseHandlerKey] = true this._closeQ.unshift(func, callback.bind(this)) function callback (err) { @@ -240,7 +243,6 @@ Boot.prototype.close = function (func) { this.ready(() => { this._error = null this._closeQ.push(func) - this._thereIsCloseCb = true process.nextTick(this._closeQ.resume.bind(this._closeQ)) }) @@ -305,21 +307,25 @@ function callWithCbOrNextTick (func, cb, context) { function closeWithCbOrNextTick (func, cb, context) { context = this._server - if (this._closeQ.length() === 0 && this._thereIsCloseCb) { - if (func.length === 0 || func.length === 1) { + var isOnCloseHandler = func[this._isOnCloseHandlerKey] + if (func.length === 0 || func.length === 1) { + if (isOnCloseHandler) { + func(context) + } else { func(this._error) - process.nextTick(cb) - } else if (func.length === 2) { - func(this._error, cb) + } + process.nextTick(cb) + } else if (func.length === 2) { + if (isOnCloseHandler) { + func(context, cb) } else { - func(this._error, context, cb) + func(this._error, cb) } } else { - if (func.length === 0 || func.length === 1) { - func(context) - process.nextTick(cb) - } else { + if (isOnCloseHandler) { func(context, cb) + } else { + func(this._error, context, cb) } } } diff --git a/example.js b/example.js index c3c8b12..32ff2a6 100644 --- a/example.js +++ b/example.js @@ -4,7 +4,11 @@ const avvio = require('.')() avvio .use(first, { hello: 'world' }) - .after((cb) => { + .after((err, cb) => { + if (err) { + console.log('something bad happened') + console.log(err) + } console.log('after first and second') cb() }) @@ -22,7 +26,8 @@ avvio function first (instance, opts, cb) { console.log('first loaded', opts) - instance.use(second, cb) + instance.use(second) + cb() } function second (instance, opts, cb) { diff --git a/test/close.test.js b/test/close.test.js index 7449026..9b8e49a 100644 --- a/test/close.test.js +++ b/test/close.test.js @@ -186,6 +186,32 @@ test('onClose should handle errors', (t) => { }) }) +test('#54 close handlers should receive same parameters when queue is not empty', (t) => { + t.plan(6) + + const context = { test: true } + const app = boot(context) + + app.use(function (server, opts, done) { + done() + }) + app.on('start', () => { + app.close((err, done) => { + t.is(err, null) + t.pass('Closed in the correct order') + setImmediate(done) + }) + app.close(err => { + t.is(err, null) + t.pass('Closed in the correct order') + }) + app.close(err => { + t.is(err, null) + t.pass('Closed in the correct order') + }) + }) +}) + test('onClose should handle errors / 2', (t) => { t.plan(4)