Dark mode
child_process
child_process เป็นโมดูลในตัวของ Node.js ที่ช่วยให้เราสามารถเรียกใช้โปรแกรมหรือคำสั่งภายนอก Node.js ได้ เช่น คำสั่งของระบบปฏิบัติการ หรือโปรแกรมอื่นๆ ที่ติดตั้งในเครื่อง
import { exec, execFile, spawn, fork, execSync, spawnSync } from 'node:child_process';
API | คำอธิบาย | ลักษณะ | คำอธิบายเพิ่มเติม |
---|---|---|---|
exec | รันคำสั่งผ่าน shell | Asynchronous | เหมาะสำหรับคำสั่งที่มีผลลัพธ์ขนาดเล็ก ทำงานผ่าน shell จึงมีความเสี่ยงด้าน shell injection |
execFile | รันไฟล์โปรแกรมโดยตรงไม่ผ่าน shell | Asynchronous | ปลอดภัยกว่า exec เพราะไม่เปิดช่องโหว่ shell injection เหมาะกับการเรียกใช้โปรแกรมที่เชื่อถือได้ |
spawn | รันโปรแกรมและจัดการ stream ข้อมูล | Asynchronous | เหมาะกับงานที่มีข้อมูลเข้า/ออกขนาดใหญ่ ควบคุม stream ได้อย่างละเอียด |
fork | สร้าง Node.js process ใหม่ | Asynchronous | ออกแบบเฉพาะสำหรับสร้าง Node.js processes มีช่องทางการสื่อสารพิเศษระหว่าง parent-child |
execSync | รันคำสั่งผ่าน shell แบบ blocking | Synchronous | ทำงานแบบ blocking ทำให้โค้ดหยุดรอจนกว่าคำสั่งจะเสร็จสิ้น ใช้กับคำสั่งที่ต้องการผลลัพธ์ทันที |
spawnSync | รันโปรแกรมแบบ blocking | Synchronous | เวอร์ชัน 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}`);
});