child_process: Avoid extra copy for string stdio
authorisaacs <i@izs.me>
Wed, 28 Aug 2013 00:28:27 +0000 (17:28 -0700)
committerisaacs <i@izs.me>
Wed, 28 Aug 2013 00:28:57 +0000 (17:28 -0700)
There's no need to create a new Buffer instance if we're just going to
immediately call toString() at the end anyway.  Better to create a
string up front, and setEncoding() on the streams, and do a string
concatenation instead.

lib/child_process.js

index 9c63154..33928a9 100644 (file)
@@ -611,8 +611,18 @@ exports.execFile = function(file /* args, options, callback */) {
     windowsVerbatimArguments: !!options.windowsVerbatimArguments
   });
 
-  var _stdout = [];
-  var _stderr = [];
+  var encoding;
+  var _stdout;
+  var _stderr;
+  if (options.encoding !== 'buffer' && Buffer.isEncoding(options.encoding)) {
+    encoding = options.encoding;
+    _stdout = '';
+    _stderr = '';
+  } else {
+    _stdout = [];
+    _stderr = [];
+    encoding = null;
+  }
   var stdoutLen = 0;
   var stderrLen = 0;
   var killed = false;
@@ -633,13 +643,14 @@ exports.execFile = function(file /* args, options, callback */) {
     if (!callback) return;
 
     // merge chunks
-    var stdout = Buffer.concat(_stdout);
-    var stderr = Buffer.concat(_stderr);
-
-    if (Buffer.isEncoding(options.encoding)) {
-      // convert to strings
-      stdout = stdout.toString(options.encoding);
-      stderr = stderr.toString(options.encoding);
+    var stdout;
+    var stderr;
+    if (!encoding) {
+      stdout = Buffer.concat(_stdout);
+      stderr = Buffer.concat(_stderr);
+    } else {
+      stdout = _stdout;
+      stderr = _stderr;
     }
 
     if (ex) {
@@ -683,25 +694,38 @@ exports.execFile = function(file /* args, options, callback */) {
   }
 
   child.stdout.addListener('data', function(chunk) {
-    _stdout.push(chunk);
     stdoutLen += chunk.length;
 
     if (stdoutLen > options.maxBuffer) {
       ex = new Error('stdout maxBuffer exceeded.');
       kill();
+    } else {
+      if (!encoding)
+        _stdout.push(chunk);
+      else
+        _stdout += chunk;
     }
   });
 
   child.stderr.addListener('data', function(chunk) {
-    _stderr.push(chunk);
     stderrLen += chunk.length;
 
     if (stderrLen > options.maxBuffer) {
       ex = new Error('stderr maxBuffer exceeded.');
       kill();
+    } else {
+      if (!encoding)
+        _stderr.push(chunk);
+      else
+        _stderr += chunk;
     }
   });
 
+  if (encoding) {
+    child.stderr.setEncoding(encoding);
+    child.stdout.setEncoding(encoding);
+  }
+
   child.addListener('close', exithandler);
   child.addListener('error', errorhandler);