Skip to content

Commit

Permalink
http: optimize outgoing requests
Browse files Browse the repository at this point in the history
This commit does some small optimization changes on
`lib/_http_outgoing.js`. These include switching from `while` loops to
`for` loops, moving away from `util` to `typeof` checks, and removing
dead code. It also includes variable caches to avoid lookups and
generic style changes. All in all, much faster execution.

It gets an across the board increase in req/sec on the benchmarks,
from my experience about a 10% increase.

PR-URL: #605
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Nicu Micleușanu <micnic90@gmail.com>
Reviewed-By: Christian Vaagland Tellnes <christian@tellnes.com>
Reviewed-By: Brian White <mscdex@mscdex.net>
  • Loading branch information
brendanashworth committed Mar 4, 2015
1 parent 7b3b8ac commit 08133f4
Showing 1 changed file with 44 additions and 28 deletions.
72 changes: 44 additions & 28 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ exports.OutgoingMessage = OutgoingMessage;
OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
if (callback)
this.on('timeout', callback);

if (!this.socket) {
this.once('socket', function(socket) {
socket.setTimeout(msecs);
Expand Down Expand Up @@ -133,32 +134,36 @@ OutgoingMessage.prototype._writeRaw = function(data, encoding, callback) {
return true;
}

if (this.connection &&
this.connection._httpMessage === this &&
this.connection.writable &&
!this.connection.destroyed) {
var connection = this.connection;
if (connection &&
connection._httpMessage === this &&
connection.writable &&
!connection.destroyed) {
// There might be pending data in the this.output buffer.
while (this.output.length) {
if (!this.connection.writable) {
this._buffer(data, encoding, callback);
return false;
var outputLength = this.output.length;
if (outputLength > 0) {
var output = this.output;
var outputEncodings = this.outputEncodings;
var outputCallbacks = this.outputCallbacks;
for (var i = 0; i < outputLength; i++) {
connection.write(output[i], outputEncodings[i],
outputCallbacks[i]);
}
var c = this.output.shift();
var e = this.outputEncodings.shift();
var cb = this.outputCallbacks.shift();
this.connection.write(c, e, cb);

this.output = [];
this.outputEncodings = [];
this.outputCallbacks = [];
}

// Directly write to socket.
return this.connection.write(data, encoding, callback);
} else if (this.connection && this.connection.destroyed) {
return connection.write(data, encoding, callback);
} else if (connection && connection.destroyed) {
// The socket was destroyed. If we're still trying to write to it,
// then we haven't gotten the 'close' event yet.
return false;
} else {
// buffer, as long as we're not destroyed.
this._buffer(data, encoding, callback);
return false;
return this._buffer(data, encoding, callback);
}
};

Expand All @@ -183,8 +188,6 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
messageHeader: firstLine
};

var field, value;

if (headers) {
var keys = Object.keys(headers);
var isArray = Array.isArray(headers);
Expand Down Expand Up @@ -365,14 +368,16 @@ OutgoingMessage.prototype._renderHeaders = function() {
throw new Error('Can\'t render headers after they are sent to the client.');
}

if (!this._headers) return {};
var headersMap = this._headers;
if (!headersMap) return {};

var headers = {};
var keys = Object.keys(this._headers);
var keys = Object.keys(headersMap);
var headerNames = this._headerNames;

for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
headers[this._headerNames[key]] = this._headers[key];
headers[headerNames[key]] = headersMap[key];
}
return headers;
};
Expand Down Expand Up @@ -571,13 +576,24 @@ OutgoingMessage.prototype._finish = function() {
// This function, outgoingFlush(), is called by both the Server and Client
// to attempt to flush any pending messages out to the socket.
OutgoingMessage.prototype._flush = function() {
if (this.socket && this.socket.writable) {
var ret;
while (this.output.length) {
var data = this.output.shift();
var encoding = this.outputEncodings.shift();
var cb = this.outputCallbacks.shift();
ret = this.socket.write(data, encoding, cb);
var socket = this.socket;
var outputLength, ret;

if (socket && socket.writable) {
// There might be remaining data in this.output; write it out
outputLength = this.output.length;
if (outputLength > 0) {
var output = this.output;
var outputEncodings = this.outputEncodings;
var outputCallbacks = this.outputCallbacks;
for (var i = 0; i < outputLength; i++) {
ret = socket.write(output[i], outputEncodings[i],
outputCallbacks[i]);
}

this.output = [];
this.outputEncodings = [];
this.outputCallbacks = [];
}

if (this.finished) {
Expand Down

0 comments on commit 08133f4

Please sign in to comment.