Node.js的child_process模塊中有兩個方法spawn和exec棚瘟,這兩個方法都可以被用來開啟一個子進程來執(zhí)行其他的程序。一些Node.js的新手常常對這個兩個方法感到很困惑:既然兩個方法的功能一樣偎蘸,那么究竟應(yīng)該選擇哪個方法。在本文中迷雪,我們將一起來探索spawn和我exec方法的不同之處,以便你在將來能夠選擇正確的方法章咧。
child_process.spaen會返回一個帶有stdout和stderr流的對象。你可以通過stdout流來讀取子進程返回給Node.js的數(shù)據(jù)赁严。stdout擁有’data’,’end’以及一般流所具有的事件。當(dāng)你想要子進程返回大量數(shù)據(jù)給Node時疼约,比如說圖像處理,讀取二進制數(shù)據(jù)等等劝枣,你最好使用spawn方法。
child_process.spawn方法是“異步中的異步”舔腾,意思是在子進程開始執(zhí)行時溪胶,它就開始從一個流總將數(shù)據(jù)從子進程返回給Node琢唾。
下面是一個例子,比如說我們想從一個URL下載文件懒熙,我們選擇使用curl工具工扎,此時肢娘,我們就可以在Node中使用spawn運行curl工具橱健,下面是具體代碼:
// 使用curl下載文件的函數(shù)var download_file_curl = function(file_url) { // 提取文件名 var file_name = url.parse(file_url).pathname.split('/').pop(); // 創(chuàng)建一個可寫流的實例 var file = fs.createWriteStream(DOWNLOAD_DIR + file_name); // 使用spawn運行curl var curl = spawn('curl', [file_url]); // 為spawn實例添加了一個data事件 curl.stdout.on('data', function(data) { file.write(data); }); // 添加一個end監(jiān)聽器來關(guān)閉文件流 curl.stdout.on('end', function(data) { file.end(); console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR); }); // 當(dāng)子進程退出時,檢查是否有錯誤撬陵,同時關(guān)閉文件流 curl.on('exit', function(code) { if (code != 0) { console.log('Failed: ' + code); } });};
child_process.exec方法會從子進程中返回一個完整的buffer蟋定。默認(rèn)情況下驶兜,這個buffer的大小應(yīng)該是200k促王。如果子進程返回的數(shù)據(jù)大小超過了200k蝇狼,程序?qū)罎⒀冈牛瑫r顯示錯誤信息“Error:maxBuffer exceeded”颤专。你可以通過在exec的可選項中設(shè)置一個更大的buffer體積來解決這個問題,但是你不應(yīng)該這樣做,因為exec本來就不是用來返回很多數(shù)據(jù)的方法簇捍。對于有很多數(shù)據(jù)返回的情況暑塑,你應(yīng)該使用上面的spawn方法惕艳。那么exec究竟是用來做什么的呢驹愚?我們可以使用它來運行程序然后返回結(jié)果的狀態(tài)谁鳍,而不是結(jié)果的數(shù)據(jù)。
child_process.exec方法是“同步中的異步”余佛,意思是盡管exec是異步的辉巡,它一定要等到子進程運行結(jié)束以后然后一次性返回所有的buffer數(shù)據(jù)郊楣。如果exec的buffer體積設(shè)置的不夠大净蚤,它將會以一個“maxBuffer exceeded”錯誤失敗告終今瀑。
和上面一樣点把,我們現(xiàn)在還是想要從一個URL下載文件郎逃。不同的是,我們現(xiàn)在要使用wget方法而不是curl方法匀泊,此時我們就需要使用exec方法在Node中執(zhí)行wget命令探赫,同時在子進程運行完畢后返回結(jié)果信息伦吠。下面是具體代碼:
// 使用wget下載文件的函數(shù)var download_file_wget = function(file_url) { // 提取文件名 var file_name = url.parse(file_url).pathname.split('/').pop(); // 組合wget命令 var wget = 'wget -P ' + DOWNLOAD_DIR + ' ' + file_url; // 使用exec執(zhí)行wget命令 var child = exec(wget, function(err, stdout, stderr) { if (err) throw err; else console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR); });};
現(xiàn)在,你應(yīng)該已經(jīng)很清楚spawn和exec之間的區(qū)別了∠溲ィ總結(jié)一下:當(dāng)你想要從子進程返回大量數(shù)據(jù)時使用spawn棍矛,如果只是返回簡單的狀態(tài)信息够委,那么使用exec。