huixisheng / huixisheng.github.com

前端开发者说,记录前端的故事
http://huixisheng.github.io/
12 stars 3 forks source link

spawn和exec #3

Closed huixisheng closed 7 years ago

huixisheng commented 8 years ago

谷歌搜了下网上介绍spawn和exec区别的文章还是很详细的,引用相关主要的提到的点。同时结合项目中使用过的脚步了解相关的使用方法。

spawn

spawn方法创建一个子进程来执行特定命令,用法与execFile方法类似,但是没有回调函数,只能通过监听事件,来获取运行结果。它属于异步执行,适用于子进程长时间运行的情况。来自Child Process模块

node v0.11.12相应的同步方法。记得不支持同步方法node版本中有对应的模块spawn-sync

child_process.spawnSync(command[, args][, options])
Added in: v0.11.12

早期简单实现了同步读取数据

    var cp = require('child_process');
    var assert = require('assert');
    var path = require('path');
    var input = {
        "prid" : productId
    };
    input = JSON.stringify(input);
    args = args || {};
    var requestPath = path.join(__dirname, 'queryProduct.js');
    var cmd = process.execPath;
    var _args = [requestPath, input];
    var res = cp.spawnSync(cmd, _args, {
        timeout: (args.timeout || 3000) + 1000
    });
    // console.log(res.stdout.toString('utf8'));
    return JSON.parse(res.stdout.toString('utf8'));

queryProduct.js


async.series([
    function(cb){
        conn.query(sql, function(err, res){
            var row = res[0];
            cb(null, row);
        });
    }
], function(err, result){
    if( err ){
        console.error(err.message);
        process.exit(1);
    } else {
        console.log(JSON.stringify(result[0]));
    }
    conn.end();
    process.exit(0);
});

exec

有对于的同步方法

child_process.execSync(command[, options])#
Added in: v0.11.12

child_process.execSync 使用实例,合并当前的操作分支到test,并推送到远程的test分支

#!/usr/bin/env node

// chmod +x
var child = require('child_process');
var execSync = require('child_process').execSync;

// @todo
var gstOutput = spawnSync('git branch', []);
var currentBranch = getCurrentBranch();
console.log('切换到test分支:');
var gcOutput = execSync('git checkout test');
console.log('合并分支' + currentBranch);
var megerOutPut = execSync('git merge ' + currentBranch);
console.log('推送test分支');
execSync('git pull origin test && git push origin test && npm run sync');
console.log('切换到' + currentBranch);
execSync('git checkout ' + currentBranch);

// git branch | grep "*"  简写
function getCurrentBranch(){
  var execOutput = execSync('git branch', {});
  var outputContent = execOutput.toString();
  var arr = outputContent.split('\n');
  for(var i = arr.length - 1; i >= 0; i--){
    if( arr[i].indexOf('*') >= 0 ){
      return arr[i].replace('*', '').trim();
    }
  }
  return '';
}

exec方法用于执行bash命令,它的参数是一个命令字符串。 如果用户输入恶意代码,将会带来安全风险。因此,在有用户输入的情况下,最好不使用exec方法,而是使用execFile方法。

区别

虽然在上面的文档用法中,spwan和exec的最终回调方式有区别,但是在node的实现中,其实两者的实现方式是一致的,exec也可以像spawn一样使用,只不过exec在触发stderr和stdout的data事件的时候,会把数据写到字符串中,到执行结束或者错误退出的时候通过回调函数传递出来,实现了exec这种便捷用法。来自exec与spawn方法的区别与陷阱

使用exec默认最大是200k。 超出时会报一个错误: "Error: maxBuffer exceeded"

使用node子进程spawn,exec踩过的坑 提到exec和spawn的源码区分

断点进去看后,豁然开朗,exec是对execFile的封装,execFile又是对spawn的封装。

exec和spawn的使用区分来自使用node子进程spawn,exec踩过的坑

不过exec确实比spawn在使用上面要好很多

例如我们执行一个命令

使用exec

require('child_process').exec('edp webserver start');

使用spawn

linux下这么搞

var child = require('child_process').spawn(
'/bin/sh', ['-c','edp webserver start'], { cwd: null, env: null, windowsVerbatimArguments: false } );

win下

 var child = require('child_process').spawn(
'cmd.exe', ['/s', '/c', 'edp webserver start'], { cwd: null, env: null, windowsVerbatimArguments: true } );

可见spawn还是比较麻烦的。

huixisheng commented 7 years ago

整理到https://huixisheng.github.io/nodejs-spawn-exec/