【问题标题】:Simple nodejs callback example with fs.readFile带有 fs.readFile 的简单 nodejs 回调示例
【发布时间】:2014-01-05 23:51:12
【问题描述】:

我正在尝试学习异步编程,并且在 nodeschool.io 的第 4 课中苦苦挣扎,通过回调实现异步 io。

基本上,我正在尝试使用 fs.readFile 通过回调计算文件中换行符的数量。

这是我的代码:

var fs = require('fs');
var pathToFile = process.argv[2];

function counter(callback) {
    var buffer = fs.readFile(pathToFile, function (err, data) {
    var bufferString = buffer.toString();
    var bufferStringSplit = bufferString.split('\n');
  });
  callback();
}

function logMyNumber() {
  console.log(bufferStringSplit.length-1);
}

counter(logMyNumber);

我知道一旦代码行执行完毕就会执行回调,所以不应该

var bufferString = buffer.toString();
var bufferStringSplit = bufferString.split('\n');

在 fs.readFile() 完成从磁盘读取文件后调用?

最后 callback() 调用 logMyNumber,它应该只输出文件的行数。

【问题讨论】:

  • 你的回调声明了一个变量data,但在你的回调中你引用了buffer。然后,您在另一个未声明的函数中引用bufferStringSplit。此外,counter 中的 callback 在来自readFile 的回调之外被调用,因此它将在readFile 完成之前执行。遵循回调链。

标签: javascript node.js asynchronous callback


【解决方案1】:

您遇到了几个问题,我会尽可能地概述它们

问题一:变量作用域

var fs = require('fs');
var pathToFile = process.argv[2];

function counter(callback) {
  var buffer = fs.readFile(pathToFile, function (err, data) { 
    // Both of the following variables are scoped to the callback of fs.readFile
    var bufferString = buffer.toString(); 
    var bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

function logMyNumber() {
  // Because the variables are in a closure above, bufferStringSplit is null here
  console.log(bufferStringSplit.length-1);
}

counter(logMyNumber);

解决办法:

声明模块范围内的变量:

var fs = require('fs');
var pathToFile = process.argv[2];

// These can now be accessed from anywhere within the module
var bufferString, bufferStringSplit;

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
    callback();
  });
}

// bufferStringSplit should no longer return null here
function logMyNumber() {
  console.log(bufferStringSplit.length-1);
}

问题 2:回调

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = buffer.toString(); 
    bufferStringSplit = bufferString.split('\n'); 

    // Place the callback WITHIN the other callback, otherwise they run in parallel
    callback();
  });
}

问题 3:fs.readFile API

fs.readFile 不返回任何内容,所以下面的 buffer 变量是 null

function counter(callback) {      
  var buffer = fs.readFile(pathToFile, function (err, data) {
    bufferString = buffer.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

解决办法:

function counter(callback) {      
  fs.readFile(pathToFile, function (err, data) {
    // The data argument of the fs.readFile callback is the data buffer
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

最后,代码应该是这样的:

var fs = require('fs');
var pathToFile = process.argv[2];

var bufferString, bufferStringSplit;

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
    callback();
  });
}

function logMyNumber() {
  console.log(bufferStringSplit.length-1);
}

counter(logMyNumber);

【讨论】:

  • 如果你想将bufferStringbufferStringSplit保持在全局范围之外,你可以将它们都传递到来自counter的回调中:callback( bufferString, bufferStringSplit)
  • @EmptyArsenal 这将是浏览器中需要考虑的问题,但是,节点范围保持在模块本地,因此您不必担心破坏全局范围。
  • @jibsales 好点。您是否有理由不希望实例化函数中的变量并将其传递给回调(除了没有必要的事实)?
  • 我想在函数之外定义它会消除程序每次运行时都声明一个新变量的需要,但如果你可能要处理许多异步回调,那可能是危险的。正确的?或者这不是问题?
  • @EmptyArsenal 你完全正确。如果这是一个被另一个模块使用的模块,则在模块范围内实例化变量并在模块的各种方法中操作它们可能会产生一些意想不到的行为。毕竟,封装是良好 OOP 的支柱。然而,由于 OP 的代码中存在如此多的问题,我认为深入探讨良好 OOP 设计的细节是题外话。
【解决方案2】:

对我来说同样的问题。这是我的解决方案。

var fs = require('fs');
var file = process.argv[2];

function count(pFile, callback) {
  fs.readFile(pFile, "utf8", function(err, data){
     callback(data.split("\n").length-1);
  });
}

count(file, console.log);

【讨论】:

  • 对于某些上下文,这是 npm learnyounode 包答案中给出的官方答案。
【解决方案3】:

也尝试处理错误。不确定,是否最好在最后一个回调中传播错误。我认为该功能非常基本,但无论如何我都在传播错误。

我还要说在 委派 split 更正确最后一个回调,而不是通过一个参数或类似的传递它。

var fs = require('fs');
var myfile = process.argv[2];



function solution(file, callback){
fs.readFile(file, "utf-8", function (err, data) {
    if (err) callback(err);
    callback(null, data)
});
}

function mycallback(err,data){
  if (err) callback(err) console.error(err);
  return data.split('\n').length-1);
}

solution(myfile,mycallback)

【讨论】:

    猜你喜欢
    • 2013-11-13
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 2018-05-03
    • 1970-01-01
    相关资源
    最近更新 更多