From: Trevor Norris Date: Thu, 5 Mar 2015 21:07:27 +0000 (-0700) Subject: node: allow multiple arguments passed to nextTick X-Git-Tag: v1.8.1~19 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=10e31ba56c676bdcad39ccad22ea9117733b8eb5;p=platform%2Fupstream%2Fnodejs.git node: allow multiple arguments passed to nextTick PR-URL: https://github.com/iojs/io.js/pull/1077 Reviewed-by: Colin Ihrig --- diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 8f22b3d..004958e 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -687,7 +687,7 @@ This will generate: `heapTotal` and `heapUsed` refer to V8's memory usage. -## process.nextTick(callback) +## process.nextTick(callback[, arg][, ...]) * `callback` {Function} diff --git a/lib/_debugger.js b/lib/_debugger.js index 0517ed0..f1885b2 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -587,9 +587,7 @@ Client.prototype.mirrorObject = function(handle, depth, cb) { } else { val = handle; } - process.nextTick(function() { - cb(null, val); - }); + process.nextTick(cb, null, val); }; diff --git a/lib/_http_client.js b/lib/_http_client.js index 82bab78..daa37ef 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -166,11 +166,8 @@ ClientRequest.prototype._implicitHeader = function() { }; ClientRequest.prototype.abort = function() { - var self = this; if (this.aborted === undefined) { - process.nextTick(function() { - self.emit('abort'); - }); + process.nextTick(emitAbortNT, this); } // Mark as aborting so we can avoid sending queued request data // This is used as a truthy flag elsewhere. The use of Date.now is for @@ -194,6 +191,11 @@ ClientRequest.prototype.abort = function() { }; +function emitAbortNT(self) { + self.emit('abort'); +} + + function createHangUpError() { var error = new Error('socket hang up'); error.code = 'ECONNRESET'; @@ -440,12 +442,14 @@ function responseOnEnd() { socket.removeListener('error', socketErrorListener); // Mark this socket as available, AFTER user-added end // handlers have a chance to run. - process.nextTick(function() { - socket.emit('free'); - }); + process.nextTick(emitFreeNT, socket); } } +function emitFreeNT(socket) { + socket.emit('free'); +} + function tickOnSocket(req, socket) { var parser = parsers.alloc(); req.socket = socket; @@ -478,18 +482,18 @@ function tickOnSocket(req, socket) { } ClientRequest.prototype.onSocket = function(socket) { - var req = this; - - process.nextTick(function() { - if (req.aborted) { - // If we were aborted while waiting for a socket, skip the whole thing. - socket.emit('free'); - } else { - tickOnSocket(req, socket); - } - }); + process.nextTick(onSocketNT, this, socket); }; +function onSocketNT(req, socket) { + if (req.aborted) { + // If we were aborted while waiting for a socket, skip the whole thing. + socket.emit('free'); + } else { + tickOnSocket(req, socket); + } +} + ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) { // This function is for calls that need to happen once the socket is // connected and writable. It's an important promisy thing for all the socket diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 3102261..8859055 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -406,14 +406,9 @@ Object.defineProperty(OutgoingMessage.prototype, 'headersSent', { OutgoingMessage.prototype.write = function(chunk, encoding, callback) { - var self = this; - if (this.finished) { var err = new Error('write after end'); - process.nextTick(function() { - self.emit('error', err); - if (callback) callback(err); - }); + process.nextTick(writeAfterEndNT, this, err, callback); return true; } @@ -455,11 +450,7 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) { if (this.connection && !this.connection.corked) { this.connection.cork(); - var conn = this.connection; - process.nextTick(function connectionCork() { - if (conn) - conn.uncork(); - }); + process.nextTick(connectionCorkNT, this.connection); } this._send(len.toString(16), 'binary', null); this._send(crlf_buf, null, null); @@ -475,6 +466,18 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) { }; +function writeAfterEndNT(self, err, callback) { + self.emit('error', err); + if (callback) callback(err); +} + + +function connectionCorkNT(conn) { + if (conn) + conn.uncork(); +} + + OutgoingMessage.prototype.addTrailers = function(headers) { this._trailer = ''; var keys = Object.keys(headers); diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js index 159e1f2..bf498f6 100644 --- a/lib/_stream_duplex.js +++ b/lib/_stream_duplex.js @@ -49,5 +49,9 @@ function onend() { // no more data can be written. // But allow more writes to happen in this tick. - process.nextTick(this.end.bind(this)); + process.nextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); } diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index bf73647..5600218 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -395,9 +395,7 @@ function emitReadable(stream) { debug('emitReadable', state.flowing); state.emittedReadable = true; if (state.sync) - process.nextTick(function() { - emitReadable_(stream); - }); + process.nextTick(emitReadable_, stream); else emitReadable_(stream); } @@ -419,9 +417,7 @@ function emitReadable_(stream) { function maybeReadMore(stream, state) { if (!state.readingMore) { state.readingMore = true; - process.nextTick(function() { - maybeReadMore_(stream, state); - }); + process.nextTick(maybeReadMore_, stream, state); } } @@ -667,11 +663,7 @@ Readable.prototype.on = function(ev, fn) { state.emittedReadable = false; state.needReadable = true; if (!state.reading) { - var self = this; - process.nextTick(function() { - debug('readable nexttick read 0'); - self.read(0); - }); + process.nextTick(nReadingNextTick, this); } else if (state.length) { emitReadable(this, state); } @@ -682,6 +674,11 @@ Readable.prototype.on = function(ev, fn) { }; Readable.prototype.addListener = Readable.prototype.on; +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} + // pause() and resume() are remnants of the legacy readable stream API // If the user uses them, then switch into old mode. Readable.prototype.resume = function() { @@ -697,9 +694,7 @@ Readable.prototype.resume = function() { function resume(stream, state) { if (!state.resumeScheduled) { state.resumeScheduled = true; - process.nextTick(function() { - resume_(stream, state); - }); + process.nextTick(resume_, stream, state); } } @@ -883,13 +878,15 @@ function endReadable(stream) { if (!state.endEmitted) { state.ended = true; - process.nextTick(function() { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } - }); + process.nextTick(endReadableNT, state, stream); + } +} + +function endReadableNT(state, stream) { + // Check that we didn't get one last unshift. + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); } } diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index c02b773..da65ddb 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -158,9 +158,7 @@ function writeAfterEnd(stream, cb) { var er = new Error('write after end'); // TODO: defer error events consistently everywhere, not just the cb stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); + process.nextTick(cb, er); } // If we get something that is not a buffer, string, null, or undefined, @@ -178,9 +176,7 @@ function validChunk(stream, state, chunk, cb) { !state.objectMode) { var er = new TypeError('Invalid non-string/buffer chunk'); stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); + process.nextTick(cb, er); valid = false; } return valid; @@ -298,10 +294,7 @@ function doWrite(stream, state, writev, len, chunk, encoding, cb) { function onwriteError(stream, state, sync, er, cb) { if (sync) - process.nextTick(function() { - state.pendingcb--; - cb(er); - }); + process.nextTick(onwriteErrorNT, state, cb, er); else { state.pendingcb--; cb(er); @@ -311,6 +304,11 @@ function onwriteError(stream, state, sync, er, cb) { stream.emit('error', er); } +function onwriteErrorNT(state, cb, er) { + state.pendingcb--; + cb(er); +} + function onwriteStateUpdate(state) { state.writing = false; state.writecb = null; @@ -339,9 +337,7 @@ function onwrite(stream, er) { } if (sync) { - process.nextTick(function() { - afterWrite(stream, state, finished, cb); - }); + process.nextTick(afterWrite, stream, state, finished, cb); } else { afterWrite(stream, state, finished, cb); } diff --git a/lib/_tls_legacy.js b/lib/_tls_legacy.js index fc0d115..3348d7f 100644 --- a/lib/_tls_legacy.js +++ b/lib/_tls_legacy.js @@ -448,17 +448,19 @@ CryptoStream.prototype.destroy = function(err) { } this._opposite.destroy(); - var self = this; - process.nextTick(function() { - // Force EOF - self.push(null); - - // Emit 'close' event - self.emit('close', err ? true : false); - }); + process.nextTick(destroyNT, this, err); }; +function destroyNT(self, err) { + // Force EOF + self.push(null); + + // Emit 'close' event + self.emit('close', err ? true : false); +} + + CryptoStream.prototype._done = function() { this._doneFlag = true; @@ -667,8 +669,6 @@ function SecurePair(context, isServer, requestCert, rejectUnauthorized, options); } - var self = this; - options || (options = {}); events.EventEmitter.call(this); @@ -737,23 +737,25 @@ function SecurePair(context, isServer, requestCert, rejectUnauthorized, this.cleartext.init(); this.encrypted.init(); - process.nextTick(function() { - /* The Connection may be destroyed by an abort call */ - if (self.ssl) { - self.ssl.start(); - - if (options.requestOCSP) - self.ssl.requestOCSP(); - - /* In case of cipher suite failures - SSL_accept/SSL_connect may fail */ - if (self.ssl && self.ssl.error) - self.error(); - } - }); + process.nextTick(securePairNT, this, options); } util.inherits(SecurePair, events.EventEmitter); +function securePairNT(self, options) { + /* The Connection may be destroyed by an abort call */ + if (self.ssl) { + self.ssl.start(); + + if (options.requestOCSP) + self.ssl.requestOCSP(); + + /* In case of cipher suite failures - SSL_accept/SSL_connect may fail */ + if (self.ssl && self.ssl.error) + self.error(); + } +} + exports.createSecurePair = function(context, isServer, @@ -835,12 +837,7 @@ exports.pipe = function pipe(pair, socket) { socket.pipe(pair.encrypted); pair.encrypted.on('close', function() { - process.nextTick(function() { - // Encrypted should be unpiped from socket to prevent possible - // write after destroy. - pair.encrypted.unpipe(socket); - socket.destroySoon(); - }); + process.nextTick(pipeCloseNT, pair, socket); }); pair.fd = socket.fd; @@ -886,3 +883,11 @@ exports.pipe = function pipe(pair, socket) { return cleartext; }; + + +function pipeCloseNT(pair, socket) { + // Encrypted should be unpiped from socket to prevent possible + // write after destroy. + pair.encrypted.unpipe(socket); + socket.destroySoon(); +} diff --git a/lib/child_process.js b/lib/child_process.js index 0fdbcf4..99da7cf 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -1015,9 +1015,7 @@ function ChildProcess() { // Do it on nextTick so that the user has one last chance // to consume the output, if for example they only want to // start reading the data once the process exits. - process.nextTick(function() { - flushStdio(self); - }); + process.nextTick(flushStdio, self); maybeClose(self); }; @@ -1075,9 +1073,7 @@ ChildProcess.prototype.spawn = function(options) { err === uv.UV_EMFILE || err === uv.UV_ENFILE || err === uv.UV_ENOENT) { - process.nextTick(function() { - self._handle.onexit(err); - }); + process.nextTick(onErrorNT, self, err); // There is no point in continuing when we've hit EMFILE or ENFILE // because we won't be able to set up the stdio file descriptors. // It's kind of silly that the de facto spec for ENOENT (the test suite) @@ -1138,6 +1134,10 @@ ChildProcess.prototype.spawn = function(options) { return err; }; +function onErrorNT(self, err) { + self._handle.onexit(err); +} + ChildProcess.prototype.kill = function(sig) { var signal; diff --git a/lib/cluster.js b/lib/cluster.js index 08230ad..10a5599 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -241,9 +241,7 @@ function masterInit() { } cluster.settings = settings; if (initialized === true) - return process.nextTick(function() { - cluster.emit('setup', settings); - }); + return process.nextTick(setupSettingsNT, settings); initialized = true; schedulingPolicy = cluster.schedulingPolicy; // Freeze policy. assert(schedulingPolicy === SCHED_NONE || schedulingPolicy === SCHED_RR, @@ -253,9 +251,7 @@ function masterInit() { return /^(--debug|--debug-brk)(=\d+)?$/.test(argv); }); - process.nextTick(function() { - cluster.emit('setup', settings); - }); + process.nextTick(setupSettingsNT, settings); // Send debug signal only if not started in debug mode, this helps a lot // on windows, because RegisterDebugHandler is not called when node starts @@ -279,6 +275,10 @@ function masterInit() { }); }; + function setupSettingsNT(settings) { + cluster.emit('setup', settings); + } + function createWorkerProcess(id, env) { var workerEnv = util._extend({}, process.env); var execArgv = cluster.settings.execArgv.slice(); @@ -376,13 +376,15 @@ function masterInit() { }); worker.process.on('internalMessage', internal(worker, onmessage)); - process.nextTick(function() { - cluster.emit('fork', worker); - }); + process.nextTick(emitForkNT, worker); cluster.workers[worker.id] = worker; return worker; }; + function emitForkNT(worker) { + cluster.emit('fork', worker); + } + cluster.disconnect = function(cb) { var workers = Object.keys(cluster.workers); if (workers.length === 0) { diff --git a/lib/dgram.js b/lib/dgram.js index 4708f4d..7d25928 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -321,16 +321,19 @@ Socket.prototype.send = function(buffer, !!callback); if (err && callback) { // don't emit as error, dgram_legacy.js compatibility - process.nextTick(function() { - var ex = exceptionWithHostPort(err, 'send', address, port); - callback(ex); - }); + process.nextTick(sendEmitErrorNT, err, address, port, callback); } } }); }; +function sendEmitErrorNT(err, address, port, callback) { + var ex = exceptionWithHostPort(err, 'send', address, port); + callback(ex); +} + + function afterSend(err) { if (err) { err = exceptionWithHostPort(err, 'send', this.address, this.port); @@ -347,14 +350,17 @@ Socket.prototype.close = function(callback) { this._handle.close(); this._handle = null; var self = this; - process.nextTick(function() { - self.emit('close'); - }); + process.nextTick(socketCloseNT, self); return this; }; +function socketCloseNT(self) { + self.emit('close'); +} + + Socket.prototype.address = function() { this._healthCheck(); diff --git a/lib/dns.js b/lib/dns.js index d39eec8..9334800 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -61,15 +61,17 @@ function makeAsync(callback) { // The API already returned, we can invoke the callback immediately. callback.apply(null, arguments); } else { - var args = arguments; - process.nextTick(function() { - callback.apply(null, args); - }); + process.nextTick(callMakeAsyncCbNT, callback, arguments); } }; } +function callMakeAsyncCbNT(callback, args) { + callback.apply(null, args); +} + + function onlookup(err, addresses) { if (err) { return this.callback(errnoException(err, 'getaddrinfo', this.hostname)); diff --git a/lib/fs.js b/lib/fs.js index 0025e6a..b6b6226 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -91,14 +91,16 @@ function nullCheck(path, callback) { er.code = 'ENOENT'; if (typeof callback !== 'function') throw er; - process.nextTick(function() { - callback(er); - }); + process.nextTick(nullCheckCallNT, callback, er); return false; } return true; } +function nullCheckCallNT(callback, er) { + callback(er); +} + // Static method to set the stats properties on a Stats object. fs.Stats = function( dev, diff --git a/lib/net.js b/lib/net.js index ac6acd6..0865e9a 100644 --- a/lib/net.js +++ b/lib/net.js @@ -267,12 +267,14 @@ function writeAfterFIN(chunk, encoding, cb) { // TODO: defer error events consistently everywhere, not just the cb self.emit('error', er); if (typeof cb === 'function') { - process.nextTick(function() { - cb(er); - }); + process.nextTick(writeAfterFINNT, cb, er); } } +function writeAfterFINNT(cb, er) { + cb(er); +} + exports.Socket = Socket; exports.Stream = Socket; // Legacy naming. @@ -923,13 +925,7 @@ Socket.prototype.connect = function(options, cb) { // immediately calls net.Socket.connect() on it (that's us). // There are no event listeners registered yet so defer the // error event to the next tick. - process.nextTick(function() { - err.host = options.host; - err.port = options.port; - err.message = err.message + ' ' + options.host + ':' + options.port; - self.emit('error', err); - self._destroy(); - }); + process.nextTick(connectErrorNT, self, err, options); } else { self._unrefTimer(); connect(self, @@ -945,6 +941,15 @@ Socket.prototype.connect = function(options, cb) { }; +function connectErrorNT(self, err, options) { + err.host = options.host; + err.port = options.port; + err.message = err.message + ' ' + options.host + ':' + options.port; + self.emit('error', err); + self._destroy(); +} + + Socket.prototype.ref = function() { if (this._handle) this._handle.ref(); @@ -1183,14 +1188,17 @@ Server.prototype._listen2 = function(address, port, addressType, backlog, fd) { if (this._unref) this.unref(); - process.nextTick(function() { - // ensure handle hasn't closed - if (self._handle) - self.emit('listening'); - }); + process.nextTick(emitListeningNT, self); }; +function emitListeningNT(self) { + // ensure handle hasn't closed + if (self._handle) + self.emit('listening'); +} + + function listen(self, address, port, addressType, backlog, fd, exclusive) { exclusive = !!exclusive; diff --git a/lib/zlib.js b/lib/zlib.js index 48bb70c..4dd8b30 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -455,12 +455,13 @@ Zlib.prototype.close = function(callback) { this._handle.close(); - var self = this; - process.nextTick(function() { - self.emit('close'); - }); + process.nextTick(emitCloseNT, this); }; +function emitCloseNT(self) { + self.emit('close'); +} + Zlib.prototype._transform = function(chunk, encoding, cb) { var flushFlag; var ws = this._writableState; diff --git a/src/node.js b/src/node.js index 1339fb3..e4167cb 100644 --- a/src/node.js +++ b/src/node.js @@ -337,7 +337,10 @@ callback = tock.callback; threw = true; try { - callback(); + if (tock.args === undefined) + callback(); + else + callback.apply(null, tock.args); threw = false; } finally { if (threw) @@ -364,7 +367,10 @@ domain.enter(); threw = true; try { - callback(); + if (tock.args === undefined) + callback(); + else + callback.apply(null, tock.args); threw = false; } finally { if (threw) @@ -381,9 +387,10 @@ } while (tickInfo[kLength] !== 0); } - function TickObject(c) { + function TickObject(c, args) { this.callback = c; this.domain = process.domain || null; + this.args = args; } function nextTick(callback) { @@ -391,7 +398,14 @@ if (process._exiting) return; - nextTickQueue.push(new TickObject(callback)); + var args = undefined; + if (arguments.length > 1) { + args = []; + for (var i = 1; i < arguments.length; i++) + args.push(arguments[i]); + } + + nextTickQueue.push(new TickObject(callback, args)); tickInfo[kLength]++; } diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out index 5c0d86a..cbdc1fdb 100644 --- a/test/message/stdin_messages.out +++ b/test/message/stdin_messages.out @@ -11,7 +11,7 @@ SyntaxError: Strict mode code may not include a with statement at Socket. (node.js:*:*) at emitNone (events.js:*:*) at Socket.emit (events.js:*:*) - at _stream_readable.js:*:* + at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (node.js:*:*) 42 42 @@ -28,7 +28,7 @@ Error: hello at Socket. (node.js:*:*) at emitNone (events.js:*:*) at Socket.emit (events.js:*:*) - at _stream_readable.js:*:* + at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (node.js:*:*) [stdin]:1 @@ -43,7 +43,7 @@ Error: hello at Socket. (node.js:*:*) at emitNone (events.js:*:*) at Socket.emit (events.js:*:*) - at _stream_readable.js:*:* + at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (node.js:*:*) 100 @@ -59,7 +59,7 @@ ReferenceError: y is not defined at Socket. (node.js:*:*) at emitNone (events.js:*:*) at Socket.emit (events.js:*:*) - at _stream_readable.js:*:* + at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (node.js:*:*) [stdin]:1 diff --git a/test/parallel/test-next-tick.js b/test/parallel/test-next-tick.js index f8b5fed..1081a96 100644 --- a/test/parallel/test-next-tick.js +++ b/test/parallel/test-next-tick.js @@ -23,6 +23,13 @@ process.nextTick(function() { complete++; }); +var obj = {}; + +process.nextTick(function(a, b) { + assert.equal(a, 42); + assert.equal(b, obj); +}, 42, obj); + process.on('exit', function() { assert.equal(5, complete); process.nextTick(function() {