2015-10-26 66 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); 
}); 

希望这会给你一个替代的想法。