Node.js içinden başka bir programı çalıştırmak için node:child_process modülünü kullanırsınız. Kısa cevap şudur: çıktıyı tek parça halinde istiyorsanız ve kabuk özelliğine ihtiyacınız yoksa execFile(), uzun süren ya da çok çıktı üreten işler için akış tabanlı spawn(), kabuk sözdizimi (boru, yönlendirme, joker karakter) gerekiyorsa exec(), başka bir Node.js betiğiyle mesajlaşmanız gerekiyorsa fork() doğru seçimdir. Dördü de aslında spawn() üzerine kurulu kolaylık fonksiyonlarıdır.

Bu yazıda dört fonksiyonun farkını, çıkış kodu ve sinyal ayrımını, ENOENT gibi başlatma hatalarını, timeout ve maxBuffer sınırlarını, senkron sürümlerin olay döngüsünü nasıl durdurduğunu, kabuk enjeksiyonu riskini ve Windows ile Linux arasındaki davranış farklarını resmî belgeye dayanarak anlatıyoruz. Bütün örnekler Node.js v26.13.0 ile çalıştırıldı; alt süreç olarak çoğunlukla process.execPath (çalışan node programının yolu) kullanıldı, böylece örnekler hem Windows hem Linux üzerinde aynı sonucu verir. Modül belgede Stability: 2 - Stable olarak işaretli.

Dört fonksiyon, tek temel: spawn

Dört fonksiyon, tek temel: spawn: exec(command), execFile(file, args), spawn(command, args), fork(modulePath, args)

Belgeye göre spawn(), exec(), execFile() ve fork() asenkron çalışır ve hepsi bir ChildProcess nesnesi döndürür. Bu nesne bir EventEmitter olduğu için alt sürecin yaşam döngüsünü spawn, exit, close, error ve message olaylarıyla izlersiniz. exec() ve execFile() ek olarak, süreç bittiğinde (error, stdout, stderr) parametreleriyle çağrılan bir geri çağırma fonksiyonu kabul eder; çıktıyı sizin yerinize biriktirir.

Farkı belirleyen iki soru vardır: komut bir kabuk (Unix'te /bin/sh, Windows'ta process.env.ComSpec) içinde mi çalışacak, ve çıktıyı bellekte toplu olarak mı yoksa akış olarak mı alacaksınız? Aşağıdaki tablo belgedeki varsayılanları özetler.

FonksiyonKabukÇıktıIPC kanalıTipik kullanım
exec(command)Evet, her zamanTamponlanır, callback ile gelirYokBoru ve yönlendirme gereken kısa kabuk komutları
execFile(file, args)Hayır (shell seçeneğiyle açılabilir)Tamponlanır, callback ile gelirYokBir programı argümanlarla güvenle çalıştırmak
spawn(command, args)Hayır (shell seçeneğiyle açılabilir)Akış: stdout ve stderr streamstdio içinde ipc ileUzun süren işler, büyük çıktı
fork(modulePath, args)DesteklenmezVarsayılan olarak ebeveynden mirasHer zaman varNode.js betikleri arasında mesajlaşma

Tamponlanan fonksiyonlarda maxBuffer varsayılan olarak 1024 * 1024 bayttır; bu sınır aşılırsa alt süreç sonlandırılır. Akış tabanlı spawn() ise böyle bir sınır uygulamaz, veriyi geldikçe size verir. Stream mantığını ayrıntılı görmek için Node.js stream rehberine bakabilirsiniz.

execFile ile program çalıştırmak ve çıktıyı almak

En sık ihtiyaç, bir programı birkaç argümanla çalıştırıp çıktısını metin olarak almaktır. Bunun için execFile() fonksiyonunu util.promisify() ile Promise döndüren hale getirmek pratik bir yoldur. Belge, promisify edilmiş sürümün { stdout, stderr } nesnesiyle çözüldüğünü, oluşan ChildProcess nesnesinin de Promise'e child özelliği olarak eklendiğini söyler. Aşağıdaki örnekte ikinci çağrı, argümanları olduğu gibi yazan küçük bir argv.mjs betiğini çalıştırıyor.

javascript
// argv.mjs: aldığı argümanları olduğu gibi yazar
console.log(process.argv.slice(2));
javascript
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';

const execFileP = promisify(execFile);

// process.execPath: şu an çalışan node programının tam yolu
const { stdout } = await execFileP(process.execPath, ['--version']);
console.log(stdout.trim());
// çıktı: v26.13.0

// Kullanıcıdan gelen metin tek bir argüman olarak gider, kabuk yorumlamaz
const { stdout: out2 } = await execFileP(process.execPath, ['argv.mjs', 'rapor; echo hack', '$HOME']);
console.log(out2.trim());
// çıktı: [ 'rapor; echo hack', '$HOME' ]

İkinci çıktıya dikkat edin: rapor; echo hack ve $HOME değerleri yorumlanmadan, birer argüman olarak alt sürece ulaştı. Kabuk olmadığı için noktalı virgül komut ayırıcı, $ işareti de değişken genişletme anlamına gelmiyor. Belge de execFile() için kabuk açılmadığından G/Ç yönlendirmesi ve joker karakter genişletmesinin desteklenmediğini, ama bu yüzden exec() sürümünden biraz daha verimli olduğunu belirtir.

Çıktının sonunda satır sonu karakteri bulunduğu için trim() çağırdık. encoding seçeneği varsayılan olarak utf8 olduğundan stdout bir dize olarak gelir; encoding: 'buffer' verirseniz Buffer alırsınız. İkili veri üreten programlarda (görüntü, arşiv) Buffer kullanmak gerekir; ayrıntı için Buffer yazısına bakabilirsiniz.

spawn: çıktıyı akış olarak okumak

spawn() çıktıyı biriktirmez; subprocess.stdout ve subprocess.stderr okunabilir stream'lerdir, subprocess.stdin ise yazılabilir bir stream'dir. Bu yüzden saatlerce çalışan bir işi, büyük bir dosya üreten bir aracı ya da canlı log akışını izlemek için uygundur. Örnekte alt program olarak üç satır yazan, stderr'e bir uyarı basan ve 3 koduyla çıkan bir betik kullanıyoruz.

javascript
// uzun.mjs: üç satır yazıp 3 koduyla çıkan küçük alt program
for (let i = 1; i <= 3; i++) {
  console.log(`satır ${i}`);
}
console.error('uyarı: disk az');
process.exitCode = 3;
javascript
import { spawn } from 'node:child_process';
import { once } from 'node:events';

const cocuk = spawn(process.execPath, ['uzun.mjs']);
cocuk.stdout.setEncoding('utf8');
cocuk.stderr.setEncoding('utf8');

let cikti = '';
let hata = '';
cocuk.on('spawn', () => console.log('başladı, pid sayı mı:', typeof cocuk.pid === 'number'));
cocuk.stdout.on('data', (parca) => (cikti += parca));
cocuk.stderr.on('data', (parca) => (hata += parca));

const [kod, sinyal] = await once(cocuk, 'close');
console.log('stdout satır sayısı:', cikti.trim().split('\n').length);
console.log('stderr:', hata.trim());
console.log('close:', kod, sinyal);
console.log('exitCode:', cocuk.exitCode);
// çıktı: başladı, pid sayı mı: true
// çıktı: stdout satır sayısı: 3
// çıktı: stderr: uyarı: disk az
// çıktı: close: 3 null
// çıktı: exitCode: 3

Burada üç olay arasındaki fark önemlidir. spawn olayı süreç başarıyla oluşturulduğunda, her şeyden önce gelir. exit olayı süreç bittiğinde gelir ama belgeye göre o anda stdio akışları hâlâ açık olabilir. close olayı ise süreç bittikten ve stdio akışları kapandıktan sonra, her zaman exit olayından sonra gelir. Çıktının tamamını işledikten sonra karar vermek istiyorsanız close olayını bekleyin. Her iki olayda da code ve signal parametrelerinden biri mutlaka null dışıdır: süreç kendi çıktıysa kod, sinyalle sonlandırıldıysa sinyal adı gelir.

Belge önemli bir tuzağı da açıkça yazar: ebeveyn ile çocuk arasındaki borular sınırlı ve platforma bağlı bir kapasiteye sahiptir. Çocuk bu kapasiteden fazla veri yazar ve siz okumazsanız, çocuk süreç tamponun boşalmasını bekleyerek kilitlenir. Çıktıyla ilgilenmiyorsanız stdio: 'ignore', çıktının doğrudan terminalinize akmasını istiyorsanız stdio: 'inherit' verin.

stdio değeriAnlamı
pipe (varsayılan)Ebeveyn ile çocuk arasında boru açılır, subprocess.stdout gibi stream olarak erişilir
inheritÇocuk ebeveynin stdin, stdout ve stderr akışlarını kullanır
ignoreİlgili tanımlayıcı /dev/null benzeri bir hedefe bağlanır, çıktı atılır
ipcMesajlaşma kanalı açar, subprocess.send() kullanılabilir hale gelir (en fazla bir tane)
Sayı veya StreamEbeveyndeki açık bir dosya tanımlayıcısını ya da stream'i çocukla paylaşır

Hata durumları: çıkış kodu, ENOENT ve sinyaller

Hata durumları: çıkış kodu, ENOENT ve sinyaller

Alt süreçle ilgili iki tür başarısızlık vardır ve ikisini ayırt etmeniz gerekir. Birincisi, program çalıştı ama sıfırdan farklı bir kodla çıktı. Belgeye göre bu durumda exec() ve execFile() geri çağırmasına bir Error gelir, error.code çıkış kodunu, error.signal de süreci sonlandıran sinyali taşır. Promisify edilmiş sürüm aynı hata nesnesiyle reddedilir ve hataya stdout ile stderr özellikleri de eklenir; yani başarısız komutun çıktısını kaybetmezsiniz.

İkincisi, program hiç başlatılamadı. Komut bulunamazsa ya da cwd olarak verdiğiniz klasör yoksa belge alt sürecin ENOENT hatası yaydığını söyler. Bu hata error olayıyla gelir ve bu durumda spawn olayı hiç tetiklenmez.

javascript
import { execFile, spawn } from 'node:child_process';
import { promisify } from 'node:util';

const execFileP = promisify(execFile);

// 1) Program çalıştı ama 0 dışı kodla çıktı: promise reddedilir
try {
  await execFileP(process.execPath, ['uzun.mjs']);
} catch (err) {
  console.log(err.code, JSON.stringify(err.stdout), JSON.stringify(err.stderr));
}
// çıktı: 3 "satır 1\nsatır 2\nsatır 3\n" "uyarı: disk az\n"

// 2) Program hiç bulunamadı: 'error' olayı, code ENOENT
const yok = spawn('boyle-bir-komut-yok');
yok.on('error', (err) => {
  console.log(err.code, err.syscall);
});
// çıktı: ENOENT spawn boyle-bir-komut-yok

error olayının tetiklendiği diğer durumlar da belgede listelenir: süreç öldürülemediğinde, çocuğa mesaj gönderilemediğinde ve süreç signal seçeneğiyle iptal edildiğinde. Belge, hata oluştuktan sonra exit olayının gelebileceğini ya da gelmeyebileceğini, ikisini birden dinliyorsanız işleyicinizin iki kez çalışmasına karşı önlem almanızı önerir. Sistem hata kodlarının (ENOENT, EACCES, EPERM) genel anlamları için sistem hataları yazısına bakabilirsiniz.

Sinyalle sonlanan süreçlerde exitCode değeri null olur, signalCode ise sinyal adını taşır. Belge, bu sinyali POSIX çıkış koduna çevirmek için util.convertProcessSignalToExitCode() fonksiyonunu gösterir. Kendi betiğinizin çıkış kodunu nasıl ayarlayacağınızı process.argv ve çıkış kodları yazısında anlattık.

Zaman aşımı, maxBuffer ve senkron sürümler

Bir alt sürecin sonsuza kadar asılı kalmasını istemezsiniz. timeout seçeneği sıfırdan büyükse, süreç bu kadar milisaniyeden uzun çalıştığında ebeveyn ona killSignal seçeneğindeki sinyali (varsayılan SIGTERM) gönderir. Çok konuşan bir programın belleğinizi doldurmasını da maxBuffer ile sınırlarsınız. Senkron spawnSync() ise sonucu tek bir nesne olarak döndürür ve input seçeneğiyle çocuğun stdin akışına veri yazmanıza izin verir. Aşağıdaki örnekte buyuk.mjs, stdin'den okuduğunu büyük harfe çeviren küçük bir betiktir.

javascript
// buyuk.mjs: stdin'den gelen metni büyük harfe çevirip yazar
let veri = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', (p) => (veri += p));
process.stdin.on('end', () => process.stdout.write(veri.toLocaleUpperCase('tr-TR')));
javascript
import { spawnSync, execFile } from 'node:child_process';

// spawnSync: input stdin'e yazılır, sonuç tek bir nesne olarak döner
const sonuc = spawnSync(process.execPath, ['buyuk.mjs'], {
  input: 'merhaba dünya',
  encoding: 'utf8',
});
console.log(sonuc.status, sonuc.signal, JSON.stringify(sonuc.stdout));
// çıktı: 0 null "MERHABA DÜNYA"

// maxBuffer aşılırsa çocuk sonlandırılır, çıktı kesilir
execFile(process.execPath, ['-p', "'x'.repeat(5000)"], { maxBuffer: 1000 }, (err, stdout) => {
  console.log(err.code);
  console.log(err.message);
  console.log('gelen bayt:', stdout.length);
});
// çıktı: ERR_CHILD_PROCESS_STDIO_MAXBUFFER
// çıktı: stdout maxBuffer length exceeded
// çıktı: gelen bayt: 1000

// timeout: süre dolunca killSignal (varsayılan SIGTERM) gönderilir
execFile(process.execPath, ['-e', 'setTimeout(() => {}, 10000)'], { timeout: 300 }, (err) => {
  console.log('killed:', err.killed, 'signal:', err.signal, 'code:', err.code);
});
// çıktı: killed: true signal: SIGTERM code: null

Zaman aşımında err.killed değeri true, err.code değeri null, sinyal de SIGTERM oldu; bu çıktı Windows üzerinde alındı. maxBuffer için belge bir Unicode uyarısı yapar: sınır karakter değil bayt sayısıdır. UTF-8 ile kodlanmış çok baytlı karakterler (Türkçe harfler dahil) sınıra beklediğinizden önce ulaşır. Örnekte 1000 baytlık sınır aşıldığında çocuk sonlandırıldı ve elimize yalnızca ilk 1000 bayt geçti.

execSync(), execFileSync() ve spawnSync(), alt süreç tamamen kapanana kadar geri dönmez. Belge, bu bloklayıcı çağrıların genel amaçlı betiklerde ve uygulama açılışında yapılandırma yüklerken işe yaradığını, ama olay döngüsünü durdurdukları için performansı ciddi biçimde etkileyebildiğini söyler. Node.js Learn rehberi de bu üç fonksiyonu bir sunucuda kaçınılması gereken senkron API'ler arasında sayar. Ayrıca execSync() ve execFileSync() zaman aşımında ya da sıfırdan farklı çıkış kodunda hata fırlatır; hata nesnesi spawnSync() sonucunun tamamını içerir. Olay döngüsünü bloklamanın sonuçlarını Node.js performans yazısında ele aldık.

fork ve IPC ile Node.js süreçleri arasında mesajlaşma

fork(), yeni bir Node.js süreci başlatan özel bir spawn() çağrısıdır. Fark, iki süreç arasında hazır bir IPC (süreçler arası iletişim) kanalının kurulmasıdır: ebeveyn subprocess.send() ile, çocuk process.send() ile mesaj gönderir; karşı taraf bunları message olayıyla alır. Varsayılan serileştirme JSON'dır; belge, mesajın serileştirilip yeniden ayrıştırıldığını ve bu yüzden gönderdiğinizle birebir aynı olmayabileceğini hatırlatır.

javascript
import { fork } from 'node:child_process';

if (process.argv[2] === 'isci') {
  // Çocuk taraf: process.send ile ebeveyne cevap verir
  process.on('message', (mesaj) => {
    const toplam = mesaj.sayilar.reduce((a, b) => a + b, 0);
    process.send({ toplam, bagli: process.connected });
    process.disconnect(); // kanal kapanınca çocuk doğal olarak biter
  });
} else {
  const cocuk = fork(import.meta.filename, ['isci']);
  cocuk.on('message', (cevap) => {
    console.log('ebeveyn aldı:', cevap);
  });
  cocuk.on('exit', (kod) => console.log('çocuk çıktı, kod:', kod));
  cocuk.send({ sayilar: [4, 8, 15, 16, 23, 42] });
}
// çıktı: ebeveyn aldı: { toplam: 108, bagli: true }
// çıktı: çocuk çıktı, kod: 0

Örnekte aynı dosya hem ebeveyn hem çocuk olarak çalışıyor; hangi rolde olduğunu process.argv[2] ile anlıyor. Çocuk işini bitirince process.disconnect() çağırıyor, kanal kapanıyor ve süreç başka bir iş kalmadığı için kendiliğinden çıkıyor. Belgeye göre çocuk bir message ya da disconnect dinleyicisi kaydedene kadar IPC kanalı unref() durumundadır, yani yalnızca açık kanal yüzünden süreç ayakta kalmaz.

Map, Set, BigInt ya da Buffer göndermeniz gerekiyorsa serialization: 'advanced' seçeneği yapılandırılmış klonlamaya dayalı daha güçlü bir biçim sunar. Belge bu biçimin JSON'un tam bir üst kümesi olmadığını ve performansın verinin yapısına göre değişebileceğini de belirtir. Bir uyarı daha: fork ile açılan her çocuk kendi belleğine ve kendi V8 örneğine sahip bağımsız bir süreçtir, belge çok sayıda Node.js alt süreci başlatmayı önermez. Aynı süreç içinde CPU yoğun iş için worker_threads yazısına, çok çekirdekli HTTP sunucusu için cluster ve PM2 yazısına bakın.

Kabuk güvenliği: exec neden tehlikeli olabilir?

Belge exec() ve execSync() için kalın harflerle şunu yazar: temizlenmemiş kullanıcı girdisini asla bu fonksiyonlara vermeyin. Komut dizesi doğrudan kabuk tarafından işlendiği için içinde noktalı virgül, ters tırnak, $() ya da boru karakteri bulunan bir girdi, sizin istemediğiniz komutları çalıştırabilir. Aynı uyarı shell seçeneği açık olan execFile(), spawn() ve senkron sürümler için de geçerlidir.

Güvenli yol, programı kabuksuz çalıştırıp kullanıcı verisini argüman dizisinin bir elemanı olarak vermektir; yukarıdaki argv.mjs örneği bunu gösteriyordu. Node.js bu konuda bir adım daha atmış: execFile() veya spawn() çağrısına shell: true ile birlikte args dizisi vermek DEP0190 koduyla kullanımdan kaldırıldı. Belgeye göre bu, v24.0.0 ile çalışma zamanı uyarısına dönüştü; çünkü bu durumda argümanlar kaçışlanmadan yalnızca boşlukla birleştirilir.

javascript
import { execFile } from 'node:child_process';

// shell: true ile args dizisi vermek DEP0190 uyarısı üretir
execFile('echo', ['merhaba'], { shell: true }, (err, stdout) => {
  console.log('çıktı:', stdout.trim());
});
// çıktı: (node:PID) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
// çıktı: (Use `node --trace-deprecation ...` to show where the warning was created)
// çıktı: çıktı: merhaba

Uyarı stderr'e yazılır, PID değeri her çalıştırmada değişir. Kullanımdan kaldırma uyarılarının türlerini ve nasıl yönetildiğini deprecation uyarıları yazısında anlattık. Kabuk özelliği gerçekten gerekiyorsa (boru, yönlendirme), komut dizesini sabit tutun ve değişken kısmı kabuğa hiç sokmayın; örneğin girdiyi stdin üzerinden verin.

Windows ve Linux arasındaki farklar

Windows ve Linux arasındaki farklar: .bat ve .cmd dosyaları, Varsayılan kabuk, Ortam değişkenleri, Sinyaller

Belge, platforma göre değişen davranışları açıkça listeler; aynı kodun iki sistemde farklı sonuç vermesinin en yaygın sebepleri bunlardır:

  • .bat ve .cmd dosyaları: Windows'ta bu dosyalar terminal olmadan kendi başlarına çalıştırılamaz, bu yüzden execFile() ile başlatılamaz. Belgedeki yollar exec() kullanmak ya da cmd.exe programını /c argümanıyla başlatmaktır. spawn() ile shell seçeneği de mümkündür ama DEP0190 yüzünden önerilmez. Dosya adında boşluk varsa tırnak içine alınmalıdır.
  • Varsayılan kabuk: Unix'te /bin/sh, Windows'ta process.env.ComSpec kullanılır; ComSpec yoksa yedek olarak cmd.exe devreye girer. Kabuk Unix tarafında -c, cmd.exe tarafında /d /s /c anahtarlarını anlamalıdır.
  • Ortam değişkenleri: Windows'ta değişken adları büyük küçük harfe duyarsızdır. env nesnesinde hem PATH hem Path varsa Node.js anahtarları sıralar ve yalnızca ilk eşleşeni çocuğa geçirir.
  • Sinyaller: Windows'ta POSIX sinyalleri yoktur. SIGKILL, SIGTERM, SIGINT ve SIGQUIT (ve Windows'ta adı bilinen diğer sinyaller) süreci zorla ve aniden sonlandırır. SIGWINCH için kill() ENOSYS fırlatır; Windows'ta karşılığı olmayan bir ad (örneğin SIGSTOP) ERR_UNKNOWN_SIGNAL hatası verir.
  • Torun süreçler: Linux'ta bir çocuğu öldürmek, onun başlattığı alt süreçleri öldürmez. Bu özellikle shell seçeneğiyle ya da bir kabuk içinden başlatılan programlarda görülür; kabuk ölür ama içindeki program çalışmaya devam edebilir.
  • detached: Windows'ta detached: true, çocuğun ebeveyn çıktıktan sonra da çalışmasını sağlar ve çocuğa ayrı bir konsol penceresi açar. Diğer platformlarda çocuk yeni bir süreç grubunun ve oturumun lideri yapılır.

Arka planda bağımsız süreç: detached ve unref

Bazen ebeveyn süreç işini bitirip çıkarken, başlattığı bir işin arka planda devam etmesini istersiniz. Belge bunun için üç parçanın birlikte gerektiğini anlatır: detached: true, ebeveynin terminaline bağlı olmayan bir stdio yapılandırması (örneğin 'ignore' ya da bir log dosyası) ve ebeveynin çocuğu beklememesi için subprocess.unref(). Varsayılan durumda ebeveyn, ayrılmış çocuğun bile çıkmasını bekler; unref() çocuğu olay döngüsünün referans sayımından çıkarır. Arada bir IPC kanalı varsa ebeveyn yine de bağımsız çıkamaz.

javascript
import { spawn } from 'node:child_process';

// Ebeveynden bağımsız çalışacak bir arka plan işi
const is = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 500)'], {
  detached: true,
  stdio: 'ignore',   // ebeveynin terminaline bağlı kalmasın
  windowsHide: true, // Windows'ta ayrı konsol penceresi gösterme
});
is.unref(); // ebeveyn bu çocuğu beklemeden çıkabilsin
console.log('ebeveyn çıkıyor, çocuk pid var mı:', Number.isInteger(is.pid));
// çıktı: ebeveyn çıkıyor, çocuk pid var mı: true

Kalıcı servisler için bu yöntem yerine bir süreç yöneticisi kullanmak daha sağlıklıdır; sunucunuzda uygulamayı açılışta başlatıp çökünce yeniden ayağa kaldırmak için systemd servis dosyası rehberine bakabilirsiniz.

Sık yapılan hatalar

  • Kullanıcı girdisini exec() içine birleştirmek: exec('convert ' + dosyaAdi) gibi bir satır kabuk enjeksiyonuna açıktır. execFile() ya da spawn() ile argüman dizisi kullanın.
  • Çıktıyı okumadan spawn() kullanmak: Boru tamponu dolunca çocuk kilitlenir. Ya stdout'u okuyun ya stdio: 'ignore' verin.
  • Sonucu exit olayında değerlendirmek: exit geldiğinde stdout'tan gelecek son parçalar henüz ulaşmamış olabilir. Çıktının tamamı lazımsa close olayını bekleyin.
  • error olayını dinlememek: Komut bulunamazsa ChildProcess bir error olayı yayar; dinleyici yoksa bu, yakalanmamış hata olarak süreci çökertir.
  • Sunucuda execSync() kullanmak: Her istekte çağrılan senkron bir alt süreç, o süre boyunca bütün istemcileri bekletir.
  • Büyük çıktıda exec() kullanmak: Varsayılan 1 MB maxBuffer aşılınca süreç öldürülür. Büyük çıktı için spawn() ile akış olarak okuyun.
  • Windows'ta .bat dosyasını execFile() ile çağırmak: Çalışmaz; exec() ya da cmd.exe /c kullanın.
  • kill() çağrısının süreci bitirdiğini varsaymak: Belge, killed özelliğinin yalnızca sinyalin başarıyla gönderildiğini gösterdiğini, sürecin sonlandığını garanti etmediğini söyler.

Sık Sorulan Sorular

exec ile execFile arasındaki fark nedir?

exec() bir kabuk açar ve komut dizesini o kabuğa verir; boru, yönlendirme ve joker karakter kullanabilirsiniz ama girdi enjeksiyonu riski taşır. execFile() varsayılan olarak kabuk açmadan programı doğrudan başlatır, argümanları dizi olarak alır ve biraz daha verimlidir. İkisi de çıktıyı tamponlar ve aynı geri çağırma imzasını kullanır.

Alt sürecin çıktısını async/await ile nasıl beklerim?

util.promisify(execFile) ya da util.promisify(exec) ile Promise döndüren sürümü alın ve await edin. spawn() için node:events modülündeki once(cocuk, 'close') fonksiyonunu bekleyebilirsiniz. Promise ve await temelleri için async/await yazısına bakın.

Bir alt süreci iptal etmenin doğru yolu nedir?

subprocess.kill() varsayılan olarak SIGTERM gönderir. Bir AbortController sinyalini signal seçeneğiyle verirseniz abort() çağrısı kill() gibi davranır, ama geri çağırmaya bir AbortError gelir. Belge, signal seçeneğini uzun ömürlü bir süreci kaynak temizliği amacıyla kapatmak için kullanmanın DEP0209 ile kullanımdan kaldırıldığını, iptal ve zaman aşımı için ise uygun olduğunu belirtir. Ayrıntılar AbortController yazısında.

child_process mi worker_threads mi kullanmalıyım?

Dış bir programı (ffmpeg, git, bir kabuk betiği) çalıştıracaksanız child_process tek seçenektir. JavaScript ile yazılmış CPU yoğun bir işi ana thread'den almak istiyorsanız worker_threads daha hafiftir ve SharedArrayBuffer ile bellek paylaşabilir; child_process ise her çocuk için ayrı bir süreç ve ayrı bellek demektir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Node.js öğrenme rehberi · worker_threads kullanımı · Node.js stream nedir · ENOENT ve sistem hataları · cluster ve PM2