考察下面的程式碼,它用於用於輸出指定目錄下的檔案
var fs=require('fs');
function sleep(numberMillis) { //sleep方法,暂停numberMillis毫秒
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true) {
now = new Date();
if (now.getTime() > exitTime)
return;
}
}
fs.readdir(__dirname,function(err,files){ //文件读取方法
console.log('');
if(!files.length){
console.log('找不到文件 \n');
}else{
console.log('文件如下:');
function file(i){
var filename=files[i];
fs.stat(__dirname+'/'+filename,function(err,stat){
if(stat.isDirectory()){
console.log(' '+i+'文件夹:'+filename+'/...');
}else{
console.log(' '+i+'文件:'+filename+'');
}
});
i++;
//sleep(1000); //。。。。。。。。######暂停1s
if(i==files.length){
console.log('输出完毕');
}else{
file(i); //否则递归调用
}
}
file(0); //开始执行
}
});
上述程式碼輸出的結果我無法理解,按照這個程式設計的邏輯,應該先是把目錄下所有檔案都列出來,然後計數器i==files.length
後才輸出「輸出完畢」這個終結語。
如上圖所示,不但「輸出完畢」這個終結語最先輸出,而且列印順序完全是錯亂的,多次運行的列印順序也不穩定。
我在想是不是非同步呼叫有時間差,所以將上述程式碼sleep(1000)註解部分去掉,但是結果依然與我所預期不一致:「檔案如下」提示語先輸出,此後停止1s後,後續語句幾乎同時出,沒有停頓,而且「輸出完畢」這個終結語依然第一個被印出。
綜上所述,我想知道的是
為什麼列印結果不穩定,為什麼「輸出完畢」這個提示語會先被輸出?
為什麼加上sleep(1000)
這個暫停語句後,只有一開始停了1s,後面不再暫停而是同時輸出?
如何解決這個問題,即如何在修改盡可能少的情況下讓「輸出完畢」這個提示語最後輸出?
謝謝各位大佬賜教!
fs.stat
是非同步操作,所以你的輸出檔案資訊都是非同步執行的,「輸出完畢」一定是先印出來的。想同步可以用這個https://nodejs.org/docs/lates...在sleep裡加個console.log('sleep')看是不是 只輸出一次?
如果你想保證輸出文件資訊之後才輸出“輸出完畢”,第一點裡我提到的用fs.statSync估計修改比較少吧
根據@Dont的回答,確實是非同步方法調用的原因,因為fs.stat的回調函數是在事件輪詢中被調用,它一般在主程式運行間隙時候被調用,被調用時間和順序不定。使用statSync方法可以實現同步: