Electron中启动如何再启动一个Node服务

1,946 阅读1分钟

记一次遇到的问题,我们知道Electron 中主进程是在node环境中,所以打算在node环境中再启动一个node服务。但是直接使用exec命令启动就会卡主。对应的代码如下

// 启动Node server
const startServer = async () => {
  try {
    console.log('开始启动node server');
    execSync('npm run server');
    console.log('成功启动node server')
  } catch (error) {
    console.log(`启动node server 失败:${error.message}`)
  }
}


// electron 中的main.js
// 这段程序将会在 Electron 结束初始化
app.whenReady().then(async () => {
  createWindow()
  startServer()
  app.on('activate', () => {
    // 在 macOS 系统内, 如果没有已开启的应用窗口
    // 点击托盘图标时通常会重新创建一个新窗口
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
  // watchProtocol()
})

在electron 应用启动之后,会调用startServer方法,在这个方法中会使用exec执行npm run server命令,这个命令会启动一个koa的node 服务。然后启动electron 但是会发现electron应用的窗口没有正常打开,但这个node 服务已近启动起来了。并且可以正常提供接口服务 在这里插入图片描述

后来发现是应为使用了同步的命令导致的,只需要把execSync命令缓存exec或者是spawn就可以解决了。

// 启动Node server
const startServer = async () => {
  try {
    console.log('开始启动node server');
    // 使用spawn or exec来启动node服务
    //const serverProcess = spawn('node', ['startServer.js']);
    exec('npm run server');
    console.log('成功启动node server')
  } catch (error) {
    console.log(`启动node server 失败:${error.message}`)
  }
}

之所以同步的命令不行,改成异步的命令就可以。我想是因为在同步命令中,主进程创建的子进程会一直等待子进程的返回。如果子进程的返回很大,会把子进程的返回暂时存在内存中,直至子进程所有内容全部结束后一起返回给主进程。这是node 同步创建子进程的机制,但这里是启动一个服务,本身没有返回的内容。所以主进程就一直在等着子进程的返回。所以electron主进程就卡主了。而通过异步创建的子进程机制则不是这样。通过异步创建的子进程互已返回一个子进程的实例,在这个实例中有stdout、stderr这些标准输出和错误。主进程是通过监听这些事件来获取子进程中返回的信息。并且是子进程产生一部分信息就返回给主进程一部分信息。而不是主进程一直在等着子进程一起返回。所以这里就不会把主进程给阻塞住。主进程通过异步创建子进程获取子进程信息类似下面这样:

 const childProcess = spawn('node', ['startServer.js'])
  
  childProcess.stdout.on('data', (data) => {
    console.log(`stdout: ${data}`);
  });

  childProcess.stderr.on('data', (data) => {
    console.error(`stderr: ${data}`);
  });

  childProcess.on('close', (code) => {
    console.log(`child process exited with code ${code}`);
  });