回调函数的用处

时间:2011-09-08 11:13:02

标签: javascript function callback

在Javascript中,有可能定义一个函数X并将其作为参数传递给另一个函数Y.

这样的函数X称为callback function

你能解释为什么在一些明显的例子中使用回调函数是有用的(例如发送一些小提琴链接和演示)?我可以看到一个有用的东西,它的代码可读性,但我不确定,因为带回调的代码看起来更复杂。

唯一有用的是它在浏览器环境中的使用和AJAX中的异步执行吗? 那么另外的Javascript实现呢(例如Rhino)?回调在那里也有用吗?或者它们的用处是否仅取决于执行Javascript的环境?

谢谢

5 个答案:

答案 0 :(得分:9)

作为参数回调

回调非常有用,因为它们允许您使用代码“配置”某个功能。

这是一个典型的例子,它是一个排序功能,允许您指定自己的排序标准。我将使用一个函数,该函数根据某些条件返回数组的最小值,因为它比排序更简单,但它仍然可以很好地作为插图:

function min(collection, property) {
    if (collection.length == 0) {
        return null;
    }

    var minIndex = 0;
    var minValue = collection[0][property];
    for (var i = 1; i < collection.length; ++i) {
        if (minValue > collection[i][property]) {
            minValue = collection[i][property];
            minIndex = i;
        }
    }

    return collection[minIndex];
}

var items = [
    { name: "John", age: 20 }, { name: "Mary", age: 18 }
    ];

alert(min(items, 'age').name); // prints "Mary"

<强> See this code run 即可。 有什么问题?

问题是虽然我们为了创建一个可配置的min函数做了一些努力(它根据我们指定的任何属性找到了最小值),但它在一般意义上仍然非常有限,因为它只能根据一个属性找到最小值

如果我们的数据是这样的,该怎么办?

var items = [ "John/20", "Mary/18" ];

这不再是一个对象数组,而是一个格式化字符串数组。它具有与原始集合相同的数据,但具有不同的结构。因此,原始的min函数不能用于处理它。

现在我们可以编写另一个版本的min,它可以使用字符串而不是对象,但这样做是没有意义的(表示相同数据的方法有很多种)。对于一个特定情况,这可能是一个快速而又脏的解决方案,但考虑到库编写器的问题:他们如何编写一个对每个人都有用的函数,而不知道数据的结构如何每个案例?

回拨救援

简单:允许用户指定如何从数据中提取条件,使min函数更强大。这听起来非常像“给出功能代码以从数据中提取标准”,这就是我们要做的事情。 min将接受回调

function min(collection, callback) {
    if (collection.length == 0) {
        return null;
    }

    var minIndex = 0;
    var minValue = callback(collection[0]);
    for (var i = 1; i < collection.length; ++i) {
        if (minValue > callback(collection[i])) {
            minValue = callback(collection[i]);
            minIndex = i;
        }
    }

    return collection[minIndex];
}

var items = [ "John/20", "Mary/18" ];

var minItem = min(items, function(item) {
    return item.split('/')[1]; // get the "age" part
});

alert(minItem);

<强> See this code run

现在最后我们的代码可重复使用。我们可以轻松地将其配置为使用第一个第二类数据,而且只需要很少的工作量。

<强> See the callback-enabled function handle both types of data 即可。这是我们通过允许用户以回调的形式提供代码作为我们函数的一部分运行而获得的极大灵活性的结果。

异步编程中的回调

回调的另一个主要用途是启用异步编程模型。这在您安排完成操作但在操作完成之前不希望程序停止运行的所有情况下都很有用。

为了使其正常工作,您可以为操作提供回调函数并有效地告诉它:为我做这项工作,当你完成后,给我回电话。然后你可以随意做任何你喜欢的事情,知道当结果可用时你指定的功能就会运行。

这在使用AJAX的网络中最为明显:您向Web服务器发出请求,在收到响应时您以某种方式对其进行操作。您不希望在现场等待响应,因为它可能需要很长时间(例如,如果存在连接问题)并且您不希望程序在所有时间内都没有响应。

有关AJAX回调的示例,请参阅jQuery load函数的文档。

答案 1 :(得分:3)

在JavaScript中,大量函数调用是异步的(例如使用XMLHTTPRequest来执行AJAX请求)。因此,您不知道返回值何时到达,因为您的浏览器我们在后台执行其他操作。

在不导致脚本的其余部分停止运行的情况下,回调函数的概念允许您在异步调用完成它需要执行的操作后立即运行过程。

例如,假设我从某个地方请求foo.json。我会做类似(虚构代码)的事情:

ajaxGet("foo.json", function(data)
{
    doSomethingWith(data);
});
doSomethingElse();

function(data) { ... }检索到数据并且现在准备就绪时,回调函数将(ajaxGet)自行执行。在此之前,doSomethingElse()将执行而不会挂起浏览器。


要回答有关其他JavaScript环境的问题,让我们看看node.js,可以说是最受欢迎的版本。

现在,node.js是完全异步的,这意味着函数调用永远不会阻塞(理论上),因此您将不得不拥有调用回调来执行任何类型的异步I / O的回调。事实上,我会说node.js几乎是真正的延续传递方式,其中函数不返回并依赖回调来传递它们的值。

答案 2 :(得分:2)

自AJAX以来,回调在JavaScript中非常流行。 AJAX是异步调用另一个Web资源,因为你不知道什么时候会完成,应用程序不需要等待响应。相反,它会继续执行,并且您会在请求完成后立即调用回调。

这个简单的代码提供了回调,以显示从服务器检索的产品:

$.get('/service/products', function(p) {
   alert(p);
});
而且,由于JavaScript是功能语言,本质上功能在这里起着重要作用。您正在将函数传递给函数,或从函数返回函数。它对于不同的模式实现非常有用,比如

function getPersonFactory(name) {
   var create = function () {
      return new Person(name);
   }

   return create;
}

var factory = getPersonFactory('Joe');
var person = factory();

由于JavaScript的功能性和goog外观以及简单的回调编程,它发现了它对Node.js这样的框架的影响,Node.js是在IO操作上高度优化的javascript框架。

Node.js HelloWorld:

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

请参阅,它创建HTTP服务器并为每个提交到该服务器的请求提供回调。您将退出响应并结束它。非常紧凑和高效的代码。

对于硬核功能编程,你可以看一下这篇很棒的文章:

http://matt.might.net/articles/implementation-of-recursive-fixed-point-y-combinator-in-javascript-for-memoization/

答案 3 :(得分:2)

如果您进行任何类型的事件监听,回调都是不可避免的。 JavaScript和事件驱动的范例是兄弟。 Web浏览器中提供的用户交互是原因。

无论您是在Node.js中监听DOM事件,Ajax完成,文件系统访问还是HTTP请求,都必须定义在事件发生时调用的过程。

更高级的回调形式是promises,例如。


此外,回调作为迭代处理器很方便:

[ 1, 2, 3 ].forEach(function callback(val) { console.log(val); });

以下内容可以用代码点替换所有字母:

'hey hop hello'.replace(/./, function callback(s) { return s.charCodeAt(0); });

答案 4 :(得分:1)

帮助进行异步函数调用。您可以调用并将回调传递给异步函数并继续当前执行,而不是等待某些函数完成。函数完成后,执行回调。 Ajax使用回调。 This解释了Ajax如何清楚地使用回调。

以下是一些类似的主题。

Why use callback in JavaScript, what are its advantages?

How can I take advantage of callback functions for asynchronous XMLHttpRequest?