Skip to content

child_process

child_process เป็นโมดูลในตัวของ Node.js ที่ช่วยให้เราสามารถเรียกใช้โปรแกรมหรือคำสั่งภายนอก Node.js ได้ เช่น คำสั่งของระบบปฏิบัติการ หรือโปรแกรมอื่นๆ ที่ติดตั้งในเครื่อง

import { exec, execFile, spawn, fork, execSync, spawnSync } from 'node:child_process';

APIคำอธิบายลักษณะคำอธิบายเพิ่มเติม
execรันคำสั่งผ่าน shellAsynchronousเหมาะสำหรับคำสั่งที่มีผลลัพธ์ขนาดเล็ก ทำงานผ่าน shell จึงมีความเสี่ยงด้าน shell injection
execFileรันไฟล์โปรแกรมโดยตรงไม่ผ่าน shellAsynchronousปลอดภัยกว่า exec เพราะไม่เปิดช่องโหว่ shell injection เหมาะกับการเรียกใช้โปรแกรมที่เชื่อถือได้
spawnรันโปรแกรมและจัดการ stream ข้อมูลAsynchronousเหมาะกับงานที่มีข้อมูลเข้า/ออกขนาดใหญ่ ควบคุม stream ได้อย่างละเอียด
forkสร้าง Node.js process ใหม่Asynchronousออกแบบเฉพาะสำหรับสร้าง Node.js processes มีช่องทางการสื่อสารพิเศษระหว่าง parent-child
execSyncรันคำสั่งผ่าน shell แบบ blockingSynchronousทำงานแบบ blocking ทำให้โค้ดหยุดรอจนกว่าคำสั่งจะเสร็จสิ้น ใช้กับคำสั่งที่ต้องการผลลัพธ์ทันที
spawnSyncรันโปรแกรมแบบ blockingSynchronousเวอร์ชัน synchronous ของ spawn เหมาะกับสคริปต์ที่ต้องการความเรียบง่ายในการเขียนโค้ด

ตัวอย่าง

รันคำสั่ง Shell แบบง่าย

js
import { exec } from "child_process";

// รันคำสั่ง shell แสดงรายการไฟล์แบบละเอียด
exec("ls -la", (error, stdout, stderr) => {
  // ตรวจสอบว่ามีข้อผิดพลาดหรือไม่
  if (error) {
    console.error(`เกิดข้อผิดพลาด: ${error.message}`);
    return;
  }

  // แสดงข้อความที่ส่งมาทาง stderr (ถ้ามี)
  if (stderr) {
    console.error(`stderr: ${stderr}`);
  }

  // แสดงผลลัพธ์จากคำสั่ง
  console.log(`ผลลัพธ์การทำงาน:\n${stdout}`);
});

รันโปรแกรมโดยตรงเพื่อความปลอดภัย

js
import { execFile } from "child_process";

// รันคำสั่ง ls แบบละเอียดโดยส่ง arguments แยก
// ปลอดภัยกว่า exec เพราะไม่มีการ shell injection
execFile("ls", ["-la", "/home"], (error, stdout, stderr) => {
  // ตรวจสอบข้อผิดพลาด
  if (error) {
    console.error(`เกิดข้อผิดพลาด: ${error.message}`);
    return;
  }

  // แสดงข้อความจาก stderr (ถ้ามี)
  if (stderr) {
    console.error(`stderr: ${stderr}`);
  }

  // แสดงรายการไฟล์
  console.log(`รายการไฟล์ในไดเรกทอรี:\n${stdout}`);
});

จัดการข้อมูลขนาดใหญ่ด้วย Stream

js
import { spawn } from "child_process";

// รันคำสั่ง find เพื่อค้นหาไฟล์ (อาจใช้เวลานานและมีข้อมูลออกมาเยอะ)
const child = spawn("find", ["/usr", "-name", "*.log", "-type", "f"]);

// รับข้อมูลจาก stdout แบบ stream (ทีละส่วน)
child.stdout.on("data", (data) => {
  console.log(`พบไฟล์: ${data.toString().trim()}`);
});

// รับข้อมูลจาก stderr เมื่อมีข้อผิดพลาด
child.stderr.on("data", (data) => {
  console.error(`ข้อผิดพลาด: ${data.toString()}`);
});

// เมื่อโปรเซสทำงานเสร็จ
child.on("close", (code) => {
  console.log(`โปรแกรมจบการทำงานด้วยรหัส: ${code}`);
});

แยกงานประมวลผลไปทำใน Child Process

js
// ไฟล์หลัก (parent.js)
import { fork } from "child_process";

// สร้าง child process จากไฟล์ worker.js
const worker = fork("./worker.js");

// ส่งข้อความไปยัง child process
worker.send({ task: "process", data: [1, 2, 3, 4, 5] });

// รับข้อความจาก child process
worker.on("message", (message) => {
  console.log("ได้รับผลลัพธ์:", message.result);
});

// ตรวจสอบเมื่อ worker จบการทำงาน
worker.on("exit", (code) => {
  console.log(`Worker จบการทำงานด้วยรหัส: ${code}`);
});

// ไฟล์ worker.js
/*
process.on('message', (message) => {
    console.log('ได้รับงาน:', message);

    if (message.task === 'process') {
        // ประมวลผลข้อมูล (เช่น คำนวณผลรวม)
        const sum = message.data.reduce((acc, val) => acc + val, 0);

        // ส่งผลลัพธ์กลับไปยัง parent
        process.send({ result: sum, status: 'completed' });
    }
});
*/

รันคำสั่งแบบ Synchronous

js
import { execSync } from "child_process";

try {
  // รันคำสั่งและรับผลลัพธ์ทันที
  const output = execSync("ls -la").toString();
  console.log("รายการไฟล์:", output);
} catch (error) {
  console.error("เกิดข้อผิดพลาด:", error.message);
}

ค้นหาข้อมูลในไฟล์ด้วย spawnSync

js
import { spawnSync } from "child_process";

// รันคำสั่ง grep เพื่อค้นหาข้อความในไฟล์
const result = spawnSync("grep", ["error", "log.txt"]);

if (result.error) {
  console.error("เกิดข้อผิดพลาด:", result.error);
} else {
  console.log("ผลลัพธ์:", result.stdout.toString());
  console.log("รหัสการจบทำงาน:", result.status);
}

สื่อสารผ่าน Standard I/O

js
import { spawn } from "child_process";

// สร้าง child process ที่รัน Node.js script
const processor = spawn("node", ["processor.js"]);

// ส่งข้อมูลไปยัง child process ผ่าน stdin
processor.stdin.write("ข้อมูลที่ต้องการประมวลผล\n");
processor.stdin.end();

// รับผลลัพธ์จาก stdout
processor.stdout.on("data", (data) => {
  console.log(`ผลลัพธ์การประมวลผล: ${data}`);
});

// จัดการข้อผิดพลาด
processor.stderr.on("data", (data) => {
  console.error(`ข้อผิดพลาด: ${data}`);
});

processor.on("error", (error) => {
  console.error(`ไม่สามารถเริ่มโปรเซสได้: ${error.message}`);
});

รันคำสั่งพร้อมกันหลายคำสั่ง

js
import { exec } from "child_process";

// รายการคำสั่งที่ต้องการรันพร้อมกัน
const commands = [
  "node --version",
  "npm --version",
  "git --version",
];

// รันทุกคำสั่งพร้อมกันและแสดงผลลัพธ์
commands.forEach(cmd => {
  exec(cmd, (error, stdout, stderr) => {
    if (error) {
      console.error(`ไม่สามารถรันคำสั่ง ${cmd}: ${error.message}`);
      return;
    }
    console.log(`คำสั่ง: ${cmd}`);
    console.log(`ผลลัพธ์: ${stdout.trim()}`);
  });
});

จัดการสภาพแวดล้อมของ Child Process

js
import { spawn } from "child_process";

// สร้าง child process พร้อมกำหนดตัวแปรสภาพแวดล้อมและไดเรกทอรีทำงาน
const child = spawn("node", ["app.js"], {
  env: {
    ...process.env, // รวมตัวแปรสภาพแวดล้อมเดิมทั้งหมด
    NODE_ENV: "production", // เพิ่มหรือแทนที่ตัวแปรสภาพแวดล้อม
    DEBUG: "app:*",
    API_KEY: "secret-key-123",
  },
  cwd: "./projects/myapp", // กำหนดไดเรกทอรีทำงาน
  stdio: "inherit", // ใช้ stdio เดียวกับ parent process
});

child.on("exit", (code) => {
  console.log(`Child process จบการทำงานด้วยรหัส: ${code}`);
});