首页 > 其他分享 >脚手架设计2-startServer

脚手架设计2-startServer

时间:2024-11-27 19:59:49浏览次数:5  
标签:const process startServer console child 进程 设计 脚手架 port

startServer

1. 要做的事

imooc-build start命令中. 要做的事情

  1. 子进程启动 webpack-dev-serve服务. 以下是子进程启动原因

      1. 方便重启, 解决配置修改后, 无法重启的问题
      1. 避免主进程受影响, 万一子进程启动失败,报错了,不能影响主进程.可以让主进程再启动一个
    • 启动子进程用 "child_process/fork"
  2. 监听配置修改, 如果配置变了, 要 杀死原服务, 再重新启动服务

    1. 文件监听用 chokidar.js
    2. 杀死原服务: child.kill();
    3. 重新启动服务: runServer()
const chokidar = require("chokidar");
const path = require("path");
const watcher = chokidar.watch(path.resolve(__dirname, ".config.json"));
watcher.on("change", (path) => {
    console.log(path, "文件变更");
})
  1. 启动服务前, 判断端口号
      1. 设置一个默认端口
      1. 使用 detect-port判断端口号是否重复, 如果重复返回可用端口号
      1. 使用 inquirer和用户交互, 让用户确认使用新端口

2. 子进程相关

ps -ef // 查看进程信息

// 输出结果
UID        PID  PPID C STIME TTY          TIME CMD
0        12321     0 0 08:00 ?        00:00:02 /sbin/init
109      22341     0 0 08:00 ?        00:00:00 ps

命令参数

  1. ps: process status. 进程状态. process进程, status 状态.
  2. ps -A: 显示所有进程信息, -A: all
  3. ps -l: 列表显示信息. -l: list
  4. ps -p 13360: 显示PID为13360的进程状态信息. -p: 指定pid
  5. ps -u 109: 显示UID为109的进程的状态信息. -u: 指定uid

命令结果

  1. UID: userId 用户id,例如109. ps -u 109.
  2. PID: process Id, 进程id, 例如22341. ps -p 22341
  3. PPID: parent process Id. 当前进程的父进程的id.
  4. C: cpu使用率
  5. STIME: start time. 开始时间
  6. TTY: Teletypewriter, 终端类型
  7. TIME: 进程消耗的 CPU 时间
  8. CMD: command. 启动进程的命令名称或路径.

3. 子进程的使用

node的子进程主要用于执行外部命令和脚本, 而不是直接执行函数, 如果非要执行函数, 可以把函数转成字符串执行.
child_process处理子进程.

// node的子进程启动方式; 
const cp = require("child_process");

// 单独起一个子进程来执行 js文件, "--force"是命令行参数, 等同于`node ./DevService.js --force`
cp.execFile("node", ["./DevService.js", "--force"], {}, (error, stdout) =>{
    // stdout 是 DevService.js里的console的内容. DevService里的console并不会直接打印,而是传给stdout 
    console.log(error, stdout)
})

// exec里的内容是直接执行命令.
cp.exec("node ./Devservice.js --force", (error, stdout)=>{
        console.log(error, stdout)
})


// 底层方法  child子进程对象
const child = cp.spawn("node", ["./Devservice.js", "--force"])
child.stdout.on("data", data => {
    console.log(data.toString()); // data是子进程的console.log
})
child.stderr.on(data, err =>{
    console.log(err.toString()); // err是子进程的报错
})
// close 当进程结束时(js文件执行完时),触发, 
// code是进程编号, 
child.on("close", code => {
    // 根据进程编号结束进程.
    process.exit(code)
})


4. 进程和子进程的通信

RPC: remote(远程) process(进程) communicate(通信)

fork方法专门用来创建有通信能力的进程;
是专门用来执行js文件用的.

const cp = require("child_process");
// 进程和子进程的相互通信
const child =  cp.fork("./Devservice.js", ['--force'])
console.log("创建子进程");
child.on("message", data => {
    console.log("父 message", data);
})
child.send({ name: "父 send" });
child.on("close", code => {
    process.exit(code)
})
console.log("创建完毕")

// 子进程
process.on("message", msg => {
    console.log("子 message", msg);
})
process.send({ name: "子 send" });
console.log("子进程结束");

最后输出 console

创建子进程  // 父进程开始
创建完毕    // 父进程结束
子进程结束  // 子进程结束
父 message { name: '子 send' }  // 父进程的回调队列结束
子 message { name: '父 send' }  // 子进程的回调队列结束

5. 命令行交互 - Inquirer

Inquirer是专门用来与用户交互的命令行工具, commander是专门用来解析命令行参数的工具;

type的类型

  • "list", 展示选项, 让用户选择
  • "password", 输入密码, 输入内容不可见
  • "input", string 输入内容,
  • "number", number 输入数字
  • "confirm", boolean 输入Y/N
  • "checkbox", 多选, 可不选.
(async ()=>{
const inquirer = require("inquirer");
const question = {
    type: "list",  // 列表方式
    name: "val",  // 返回值的key
    message: "请选择",  // 提示信息
    choices: ["a", "b", "c"],  // 具体选项
    default: "a", // 默认值

};
const prompt = inquirer.createPromptModule();
const answer = await prompt(question); 
console.log(answer); // {val: "a"}

})()


6. 同步执行promise函数

有些函数返回的是promise(比如detect), 当我们不想用then获取返回值, 而是想同步执行,获取返回值时.

  1. 直接执行会返回promise, const val = detect(port); //返回promise
  2. 加await结构promise, const val = await detect(port); , 会提示await需要在async中.
  3. 加async, 会提示async不能在最外层.
  4. 给async加一层自执行函数. 完成.

(async ()=>{
    const newPort = await detect(port);
    // newPort就是promise解构后的返回值.
})()

7. detect-port 原理

  1. 解析传入的port, 设置最大值maxPort;
  2. 用net.Server创建一个TCP协议的请求.
  3. server.listen(port, '')测试port是否能正常启动
  4. 如果能正常启动,则用close关闭服务,并返回port.
  5. 再用server.listen测试地址为"0.0.0.0"的情况,如果还能正常启动则port可用.
  6. 如果启动失败,则port=port+1, 再试一次,直到maxPort.
const server = new net.Server();
// 请求地址为空的情况""
server.listen(port, "", () => {
    port = server.address().port;
    server.close();
    // 请求地址为本地的情况
    server.listen(port, "0.0.0.0", ()=>{
        port = server.address().port;
        server.close();
    })
})

标签:const,process,startServer,console,child,进程,设计,脚手架,port
From: https://www.cnblogs.com/bridge7839/p/18573012

相关文章