繁体   English   中英

如何避免node.js的异步行为?

[英]How to avoid async behviour of 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 ) );
});

问题是msgs异步填充,一旦forEach完成,我想获取msgs。 我该如何实现?

如果您确实想摆脱异步代码,则可以使用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);
});

我希望使异步函数看起来不那么异步的是Promises 尤其是Bluebird Promise库非常出色。 本质上,您的函数可能如下所示:

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);
});

这样可以保持异步调用的所有优势(例如,不锁定运行线程),从而使您的API快速响应。 不过,如果仅通过链接then同步,它仍可以让您编写代码“好像”。

您可以使用几种方法,

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,或者使用像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 ) );
})

@Nomi我建议更改以下内容,这将帮助您获得很多性能。

1.将文件上传从单个发布请求更改为多个发布请求。 我的意思是,您应该更改前端代码以将单独的后期请求发送到每个文件。

2.在每个JavaScript请求中保留跟踪器/计数变量。 基本上,计数器值最初与文件数相同。 每个文件完全上传后,再减少1。 并且当计数器值达到0时,您可以显示成功消息。可能的是,您可以使用promise进行此文件跟踪。

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);
});

希望这会给您一个替代的主意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM