Browse Source

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: https://github.com/iojs/io.js/pull/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>
v1.8.0-commit
Brendan Ashworth 10 years ago
parent
commit
08133f45c7
  1. 72
      lib/_http_outgoing.js

72
lib/_http_outgoing.js

@ -78,6 +78,7 @@ exports.OutgoingMessage = OutgoingMessage;
OutgoingMessage.prototype.setTimeout = function(msecs, callback) { OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
if (callback) if (callback)
this.on('timeout', callback); this.on('timeout', callback);
if (!this.socket) { if (!this.socket) {
this.once('socket', function(socket) { this.once('socket', function(socket) {
socket.setTimeout(msecs); socket.setTimeout(msecs);
@ -133,32 +134,36 @@ OutgoingMessage.prototype._writeRaw = function(data, encoding, callback) {
return true; return true;
} }
if (this.connection && var connection = this.connection;
this.connection._httpMessage === this && if (connection &&
this.connection.writable && connection._httpMessage === this &&
!this.connection.destroyed) { connection.writable &&
!connection.destroyed) {
// There might be pending data in the this.output buffer. // There might be pending data in the this.output buffer.
while (this.output.length) { var outputLength = this.output.length;
if (!this.connection.writable) { if (outputLength > 0) {
this._buffer(data, encoding, callback); var output = this.output;
return false; 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(); this.output = [];
var cb = this.outputCallbacks.shift(); this.outputEncodings = [];
this.connection.write(c, e, cb); this.outputCallbacks = [];
} }
// Directly write to socket. // Directly write to socket.
return this.connection.write(data, encoding, callback); return connection.write(data, encoding, callback);
} else if (this.connection && this.connection.destroyed) { } else if (connection && connection.destroyed) {
// The socket was destroyed. If we're still trying to write to it, // The socket was destroyed. If we're still trying to write to it,
// then we haven't gotten the 'close' event yet. // then we haven't gotten the 'close' event yet.
return false; return false;
} else { } else {
// buffer, as long as we're not destroyed. // buffer, as long as we're not destroyed.
this._buffer(data, encoding, callback); return this._buffer(data, encoding, callback);
return false;
} }
}; };
@ -183,8 +188,6 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
messageHeader: firstLine messageHeader: firstLine
}; };
var field, value;
if (headers) { if (headers) {
var keys = Object.keys(headers); var keys = Object.keys(headers);
var isArray = Array.isArray(headers); var isArray = Array.isArray(headers);
@ -365,14 +368,16 @@ OutgoingMessage.prototype._renderHeaders = function() {
throw new Error('Can\'t render headers after they are sent to the client.'); 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 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++) { for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i]; var key = keys[i];
headers[this._headerNames[key]] = this._headers[key]; headers[headerNames[key]] = headersMap[key];
} }
return headers; return headers;
}; };
@ -571,13 +576,24 @@ OutgoingMessage.prototype._finish = function() {
// This function, outgoingFlush(), is called by both the Server and Client // This function, outgoingFlush(), is called by both the Server and Client
// to attempt to flush any pending messages out to the socket. // to attempt to flush any pending messages out to the socket.
OutgoingMessage.prototype._flush = function() { OutgoingMessage.prototype._flush = function() {
if (this.socket && this.socket.writable) { var socket = this.socket;
var ret; var outputLength, ret;
while (this.output.length) {
var data = this.output.shift(); if (socket && socket.writable) {
var encoding = this.outputEncodings.shift(); // There might be remaining data in this.output; write it out
var cb = this.outputCallbacks.shift(); outputLength = this.output.length;
ret = this.socket.write(data, encoding, cb); 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) { if (this.finished) {

Loading…
Cancel
Save