node子进程调用方法-一分钟改进hexo-admin插件



在执行一些比较复杂的命令时,需要用到子进程,以避免阻塞主进程。

在使用hexo-admin插件的时候,发现作者也是用了子进程来处理deploy,并且,通过一定的设置,还能将执行进程的结果都返回给前端。

1.问题

由于仓库年久失修,发布的命令用不了,决定查看源码一看究竟。

upload successful

2.定位

打开hexo-admin的模块,找到deploy.js文件,就是此文件暴露了发布方法,我们看一下大概的结构:

var spawn = require('child_process').spawn

function once(fn) {
  var called = false
  return function () {
    if (!called) fn.apply(this, arguments)
    called = true
  }
}

module.exports = function (command, message, done) {
  done = once(done);
  var proc = spawn(command, [message], {detached: true});
  var stdout = '';
  var stderr = '';
  proc.stdout.on('data', function(data){stdout += data.toString()})
  proc.stderr.on('data', function(data){stderr += data.toString()})
  proc.on('error', function(err) {
    done(err, {stdout: stdout, stderr: stderr});
  });
  proc.on('close', function () {
    done(null, {stdout: stdout, stderr: stderr});
  });
}

module导出的就是主方法,这里有三个参数,我们关注的是第一个command和第二个message参数,从下面调用的方法—— var proc = spawn(command, [message], {detached: true});可以看出command是需要执行的命令,在后面会提到这个命令作者是直接放在配置文件中,灵活性很强,第二个message参数在这里其实是附加给command的参数,比如command是cmd.exe ,那么参数可以是’/dsf/some.bat’,具体的用法参考node文档:https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html,

查看此方法的调用,找到api.js,里面有一段使用deploy的代码,如下:

use('deploy', function(req, res, next) {
  if (req.method !== 'POST') return next()
  if (!hexo.config.admin || !hexo.config.admin.deployCommand) {
    return res.done({error: 'Config value "admin.deployCommand" not found'});
  }
  try {
    deploy(hexo.config.admin.deployCommand, req.body.message, function(err, result) {
      console.log('res', err, result);
      if (err) {
        return res.done({error: err.message || err})
      }
      res.done(result);
    });
  } catch (e) {
    console.log('EEE', e);
    res.done({error: e.message})
  }
});

从这个方法中就能明确看到,这是写的一个http接口,用的post方法,在执行deploy方法的时候,第一个参数是hexo.config.admin.deployCommand 。也就是说,需要改执行的命令方法,只要修改配置文件就可以,那这里我就填了 ‘bash’,因为需要在linux下运行。

再看第二个参数,很明显,req.body.message指向的就是post方法传的参数,这样一想就明白了,难怪会运行不起来,这个message参数传的不对,命令就执行不下去,但是我看了nodejs文档之后发现,需要执行的脚本文件名可以固定下来,这个message参数可以作为额外的参数传入。

3.解决

我想用这个deploy执行一下几个命令

#!/bin/bash
hexo clean
hexo g  
hexo d 
git add .
git commit -m "generated files on `date +'%Y-%m-%d %H:%M:%S'`"
git push -u origin master

由于commit -m中需要一个清楚的描述,我觉得这里可以把这个message参数利用起来,稍加修改,改成

#!/bin/bash
message=${1}
echo 提交内容:${message}
hexo clean
hexo g  
hexo d 
git add .
git commit -m "${message} generated files on `date +'%Y-%m-%d %H:%M:%S'`"
git push -u origin master

这样,这个bash文件就可以接受一个message参数了。那么,上面的deploy.js也需要做相应的修改,

// var proc = spawn(command, [message], {detached: true});
 var proc = spawn(command, ['deploy.sh', message], {detached: true});

仅此而已,执行的对象就固定成了deploy.sh啦,并且前端传入的message可以作为提交的摘要写入commit。

经测试,可以运行。

运行结果


文章作者: 无名小卒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 无名小卒 !
  目录