2015-10-26 108 views
0

我正在上傳多個文件並保存在某個目錄中。我的代碼如下如何避免node.js的異步行爲?

app.post('/file_upload', function (req, res) { 
    var msgs = ''; 

    req.files.forEach(function(element) { 
    var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname; 
    fs.readFile(element.path, function (err, data) { 
     fs.writeFile(fileNameToWrite, data, function (err) { 
     if(err){ 
       msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' "; 
     } 
     else{ 
       msgs += element.originalname + " Uploaded Successfully "; 
      } 
     }); 
    }); 
    },this); 
    console.log("Final Msgs: " + msgs); 
    res.end(JSON.stringify(msgs)); 
}); 

問題是封郵件被異步填充,我想封郵件一次的forEach完成。我怎樣才能做到這一點?

+0

您在這裏問的是錯誤的問題,您不想擺脫異步行爲,因爲這會導致用戶體驗失效。相反,一旦所有請求都完成,您應該找到一種方法來執行您的代碼。不幸的是,我不太瞭解節點,告訴你如何做到這一點。 –

+0

@RoryMcCrossan @RoryMcCrossan對這個問題感到抱歉這裏我沒有讀到你的答案在ajax上不要使用ASYNC FALSE你能告訴爲什麼謝謝你 – guradio

+1

這是因爲運行請求同步鎖定瀏覽器的UI。這意味着對用戶來說,瀏覽器將顯示爲鎖定狀態,並且已經崩潰,直到所有請求都完成。 –

回答

1

我會去什麼使異步功能似乎不那麼異步是Promises。特別是Bluebird promise library非常好。從本質上講,你的函數看起來是這樣的:

var Promise = require('bluebird') 
var readFile = Promise.promisify(require('fs').readFile); 

app.post('/file_upload', function (req, res) { 
    var msgs = ''; 

    req.files.forEach(function(element) { 
    var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname; 
    readFile(element.path).then(function (data) { 
     return writeFile(filenameToWrite, data); 
    }).then(function() { 
     msgs += element.originalname + " Uploaded Successfully "; 
    }).catch(function() { 
     msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' "; 
    }).then(function() { 
     console.log("Final Msgs: " + msgs); 
     res.end(JSON.stringify(msgs)); 
    }); 
    },this); 
}); 

這使異步調用的所有goodiness(例如,未鎖定的正在運行的線程),使您的API快速反應。不過,它讓你編寫代碼「好像」如果是通過鏈接then同步。

1

如果你真的想擺脫異步代碼,你可以使用writeFileSyncreadFileSync。但這不是一個好的實踐。

一個簡單的方法是使用一個回調是這樣的:

app.post('/file_upload', function (req, res) { 
    var msgs = ''; 

    function finish() { 
    console.log("Final Msgs: " + msgs); 
    res.end(JSON.stringify(msgs)); 
    } 

    var counter = 0; 

    req.files.forEach(function(element) { 
    var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname; 
    fs.readFile(element.path, function (err, data) { 
     fs.writeFile(fileNameToWrite, data, function (err) { 
     if(err){ 
       msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' "; 
     } 
     else{ 
       msgs += element.originalname + " Uploaded Successfully "; 
      } 

     // We call the finish when we write the last file 
     counter += 1; 
     if (counter == req.files.length) { 
      finish(); 
     } 
     }); 
    }); 
    },this); 
}); 
1

您可以使用幾種方法,

1.使用writefilesync,而不是fs.writeFile,這樣

req.files.forEach(function(element) { 
    var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname; 

    try { 
    fs.writeFileSync(fileNameToWrite, data); 
    msgs += element.originalname + " Uploaded Successfully "; 
    } catch(err) { 
    msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' "; 
    } 
}, this); 

2.Or使用庫,例如​​asyncnpm i async --save-dev),像這樣

var async = require('async'); 
var msgs = ''; 

async.eachSeries(req.files, function (element, next) { 
    var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname; 

    fs.readFile(element.path, function (err, data) { 
    if (err) { 
     msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' "; 
    } else { 
     msgs += element.originalname + " Uploaded Successfully "; 
    } 

    next(); 
    }); 
}, function() { 
    console.log("Final Msgs: " + msgs); 
    res.end(JSON.stringify(msgs)); 
}) 
1

@Nomi 我會建議改變下面的事情,這將幫助你獲得更多的表演NCE。

1.將文件上傳從單個帖子請求更改爲多個帖子請求。我的意思是,你應該改變你的前端代碼,向每個文件發送單獨的發佈請求。

2.在每個JavaScript請求中保留一個跟蹤器/計數變量。基本上,計數器值最初與文件數量相同。然後減少1,當每個文件完全上傳。當計數器值達到0時,您可以顯示成功消息。可能您可以使用承諾來進行此文件跟蹤。

3.修改您的服務器端代碼以處理流式傳輸模式下的文件上傳請求。您可能想要查看以下服務器端代碼。

var fs = require('fs'); 
app.post('/file_upload', function(req, res) { 
    // Read file name and extension from request header and replace 'somefile.someExtension' below. 
    var fileNameToWrite = __dirname + "\\uploads\\" + 'somefile.someExtension'; 
    var wStream = fs.createWriteStream(fileNameToWrite); 
    req.pipe(wStream); 
}); 

希望這會給你一個替代的想法。