理解函数(错误,数据)回调

时间:2013-12-18 01:04:04

标签: javascript node.js asynchronous callback

所以我对函数(错误,数据)回调如何工作感到困惑,第一个参数总是一个错误处理程序?

如果你有类似函数(x,y,z,a,b,c)的其余参数怎么样?

fs.readFile中的数据如何从代码顶行传递到底部代码行?或者换句话说,fs.readFile的输出如何被放入数据参数?

fs.readFile(pathToFile, function (err, **data**) {
    bufferString = **data**.toString();

我可以用函数(x,y)和函数(x,y,z,a,b,c)替换函数(错误,数据)

但只有第二个参数有效(数据和y),这只是javascript回调的语法吗?

例如,这是一个工作代码,用于异步读取文件并打印出给定文件的行数:

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

4 个答案:

答案 0 :(得分:4)

回调的调用者(在这种情况下是readFile方法)决定传递给回调的参数。您需要声明您的回调以匹配readFile表示它将传递给回调的内容。您可以根据需要为参数命名(您使用的名称无关紧要),但它们将按readFile决定的顺序获取值。

在这种情况下,fs.readFile()使用代码中的两个参数调用回调,如callback(err, data)中所示。

这是来自node.js docs:

的示例
fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

答案 1 :(得分:2)

通过示例易于理解...您可以编写自己的使用回调的函数版本,非常简单:

function getTwoStringsAsync(callback) {
    setTimeout(function() {
        callback("foo", "bar");
    }, 1000);
}

这里,函数getTwoStringsAsync预先假定“回调”是一个函数,它意味着签名(两个参数是字符串)。您的方法的使用者是否可以自由地遵守隐含的签名。它可以使用这些值中的一个或两个,也可以两者都不使用。但如果它假定任何两个以上的参数,那么这些参数将显示为未定义。

getTwoStringsAsync(function() { console.log("done!"); });
getTwoStringsAsync(function(first, second) { console.log("got " + first + ", " + second); });
getTwoStringsAsync(function(first, second, third) { console.log(third); });   // "undefined"

可以说是一种限制,或强度,或弱类型语言,如Javascript,功能签名将无法验证。强类型语言可能会在上面的第一次或第三次使用中生成编译器错误或警告。

答案 2 :(得分:1)

回调的参数取决于如何调用回调。例如:

var map = function(xs, f) {
  var result = [];
  for (var i=0; i<xs.length; i++) {
    // Here we call the callback function
    // with the element as context, the element as first param
    // and the index as second param.
    // Extra parameters are `undefined`
    result.push(f.call(xs[i], xs[i], i));
  }
  return result;
};

然后你就像使用它一样:

var addIdx = function(x,i){ return x+i };
map([1,2,3], addIdx); //=> [1,3,5]

答案 3 :(得分:0)

当您调用某个函数时,它可以返回单个值或抛出单个错误。

这个同步代码的“等价物”:

try {
    var data = functionCall();
    //Use data
}
catch(err) {
    console.log(err);
}

这是异步回调:

functionCallAsync(function(err, data) {
    if (err) {
         console.log(err);
    }
    else {
         //Use data
    }

});

您现在可以看到为什么在回调中使用多个值没有意义。事实上,这种模式是有害的。

例如,当使用生成器时,您只能使用单个返回值。但是,如果一些无知的图书馆作者继续并打破了回调惯例并使用了多个,那就不可能了。

async(function* () {
    try {
        //What if `functionCallAsync` was called back with multiple values?
        var data = yield functionCallAsync();
        //Use data
    }
    catch(e) {
        console.log(e);
    }
});