【问题标题】:Is safe read and then write a file asynchronously on node.js?在node.js上异步读取然后写入文件是否安全?
【发布时间】:2015-12-29 22:28:02
【问题描述】:

我有一个读取和写入日志文件的方法,所有用户的每个请求都会调用此方法,然后将日志写入文件中的请求路径。问题有两个:

  1. 考虑到并发问题,是否可以在异步模式下安全读取然后写入文件?
  2. 如果第一个问题是,下面的代码是否可以考虑并发问题?
  3. 如果第一个问题是,我该怎么办?

请忽略异常和性能问题,这是一个教学代码。


var logFile = '/tmp/logs/log.js';
app.get("/", function(req){
    var log = {path: req.path, date: new Date().getTime()};
    log(log);
});

function log(data){
    fs.exists(logFile, function(exists){
        if(exists){
            fs.readFile(logFile, function (err, data) {
                if (err){
                    throw err
                }
             var logData = JSON.parse(data.toString());
             logData.push(data);
             writeLog(logData);
            }); 
        }else{
            writeLog([data]);
        }

    });
     
}
function writeLog(base){
    fs.writeFile(logFile, JSON.stringify(base, null, '\t'), function(err) {
        if(err)
            throw err;
    }); 
}

【问题讨论】:

  • 你已经在异步读写了——readFileSyncwriteFileSync 会同步进行。
  • 对不起,如果我不清楚,我需要知道我是否可以异步完成
  • 我是说你已经使用你编写的代码了。然而,本杰明在下面提出了一个很好的观点。
  • 仅供参考,当从异步回调中抛出时,您的 throw err 不会做任何有用的事情。它不会返回到您可能拥有的任何异常处理程序。该错误基本上只是默默地停止处理。多个嵌套的异步操作,确实需要类似 Promise 的东西来进行正确的错误处理。
  • @jfriend00,是的.. 关键是在这种情况下我是否可以在异步模式下进行读/写

标签: node.js


【解决方案1】:

我强烈建议您不要只是“异步记录”,因为您希望日志根据应用中发生的事情的顺序进行排序,并且不能保证会发生这种情况如果你不以某种方式同步它。

例如,您可以使用承诺链来同步它:

var _queue = Promise.resolve();
function log(message){
  _queue = _queue.then(function(){ // chain to the queue
    return new Promise(function(resolve){ 
      fs.appendFile("/tmp/logs/log.txt", new Date() + message + "\n", function(err, data){
        if(err) console.log(err); // don't die on log exceptions
        else resolve(); // signal to the queue it can progress
      });
    });
  });
}

您现在可以调用log,它会将消息排队并为您异步写入一段时间。它永远不会占用一个以上的文件描述符或耗尽服务器。

考虑使用日志记录解决方案,而不是滚动您自己的记录器。

【讨论】:

  • 好的,所以我的文件可以接收无序的日志但永远不会损坏?
  • @deFreitas 使用此解决方案,它将始终接收有序的日志 - 这就是 .then 所做的,它将操作排队而不是仅调用 writeFile
  • 对不起,问题是我的实现。
  • @deFreitas 那么是的,可能虽然更多的写入可能会失败(虽然不会损坏)。或者打开文件的写入流并附加到该文件,这也很好(如果您在process.on("uncaughtException" 上关闭它)。
  • 如果.appendFile() 出现文件错误,您的代码永远不会解决承诺,因此它只会永远排队数据。
【解决方案2】:

在您的示例中,您已经在使用这些函数的异步版本。如果您担心操作的顺序,那么您应该使用这些函数的同步版本。

readFileSync
writeFileSync

还要注意,JSON.parse() 是一个同步操作。您可以使用async 模块并执行async.asyncify(JSON.parse(data.toString())); 使这个“异步”。

正如@BenjaminGruenbaum 所述,async.asyncify(); 实际上并没有使JSON.parse(); 的操作真正异步,但它确实为操作的控制流提供了一种更“异步”的风格。

【讨论】:

  • 如果您使用 async.asyncify,JSON.parse 将保持同步,这无济于事。稍后它将同步运行。
  • @BenjaminGruenbaum 肯定,但它会提供异步风格的控制流,并且也会消除对 try/catch 块的需要。
猜你喜欢
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多