Skip to content

Commit 08133f4

Browse files
http: optimize outgoing requests
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>
1 parent 7b3b8ac commit 08133f4

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

lib/_http_outgoing.js

+44-28
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ exports.OutgoingMessage = OutgoingMessage;
7878
OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
7979
if (callback)
8080
this.on('timeout', callback);
81+
8182
if (!this.socket) {
8283
this.once('socket', function(socket) {
8384
socket.setTimeout(msecs);
@@ -133,32 +134,36 @@ OutgoingMessage.prototype._writeRaw = function(data, encoding, callback) {
133134
return true;
134135
}
135136

136-
if (this.connection &&
137-
this.connection._httpMessage === this &&
138-
this.connection.writable &&
139-
!this.connection.destroyed) {
137+
var connection = this.connection;
138+
if (connection &&
139+
connection._httpMessage === this &&
140+
connection.writable &&
141+
!connection.destroyed) {
140142
// There might be pending data in the this.output buffer.
141-
while (this.output.length) {
142-
if (!this.connection.writable) {
143-
this._buffer(data, encoding, callback);
144-
return false;
143+
var outputLength = this.output.length;
144+
if (outputLength > 0) {
145+
var output = this.output;
146+
var outputEncodings = this.outputEncodings;
147+
var outputCallbacks = this.outputCallbacks;
148+
for (var i = 0; i < outputLength; i++) {
149+
connection.write(output[i], outputEncodings[i],
150+
outputCallbacks[i]);
145151
}
146-
var c = this.output.shift();
147-
var e = this.outputEncodings.shift();
148-
var cb = this.outputCallbacks.shift();
149-
this.connection.write(c, e, cb);
152+
153+
this.output = [];
154+
this.outputEncodings = [];
155+
this.outputCallbacks = [];
150156
}
151157

152158
// Directly write to socket.
153-
return this.connection.write(data, encoding, callback);
154-
} else if (this.connection && this.connection.destroyed) {
159+
return connection.write(data, encoding, callback);
160+
} else if (connection && connection.destroyed) {
155161
// The socket was destroyed. If we're still trying to write to it,
156162
// then we haven't gotten the 'close' event yet.
157163
return false;
158164
} else {
159165
// buffer, as long as we're not destroyed.
160-
this._buffer(data, encoding, callback);
161-
return false;
166+
return this._buffer(data, encoding, callback);
162167
}
163168
};
164169

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

186-
var field, value;
187-
188191
if (headers) {
189192
var keys = Object.keys(headers);
190193
var isArray = Array.isArray(headers);
@@ -365,14 +368,16 @@ OutgoingMessage.prototype._renderHeaders = function() {
365368
throw new Error('Can\'t render headers after they are sent to the client.');
366369
}
367370

368-
if (!this._headers) return {};
371+
var headersMap = this._headers;
372+
if (!headersMap) return {};
369373

370374
var headers = {};
371-
var keys = Object.keys(this._headers);
375+
var keys = Object.keys(headersMap);
376+
var headerNames = this._headerNames;
372377

373378
for (var i = 0, l = keys.length; i < l; i++) {
374379
var key = keys[i];
375-
headers[this._headerNames[key]] = this._headers[key];
380+
headers[headerNames[key]] = headersMap[key];
376381
}
377382
return headers;
378383
};
@@ -571,13 +576,24 @@ OutgoingMessage.prototype._finish = function() {
571576
// This function, outgoingFlush(), is called by both the Server and Client
572577
// to attempt to flush any pending messages out to the socket.
573578
OutgoingMessage.prototype._flush = function() {
574-
if (this.socket && this.socket.writable) {
575-
var ret;
576-
while (this.output.length) {
577-
var data = this.output.shift();
578-
var encoding = this.outputEncodings.shift();
579-
var cb = this.outputCallbacks.shift();
580-
ret = this.socket.write(data, encoding, cb);
579+
var socket = this.socket;
580+
var outputLength, ret;
581+
582+
if (socket && socket.writable) {
583+
// There might be remaining data in this.output; write it out
584+
outputLength = this.output.length;
585+
if (outputLength > 0) {
586+
var output = this.output;
587+
var outputEncodings = this.outputEncodings;
588+
var outputCallbacks = this.outputCallbacks;
589+
for (var i = 0; i < outputLength; i++) {
590+
ret = socket.write(output[i], outputEncodings[i],
591+
outputCallbacks[i]);
592+
}
593+
594+
this.output = [];
595+
this.outputEncodings = [];
596+
this.outputCallbacks = [];
581597
}
582598

583599
if (this.finished) {

0 commit comments

Comments
 (0)