理解回调函数的目的

4

我知道这是一个比较普遍的问题,但我已经阅读了类似的回答,但我找不到更全面的概述。我刚开始接触回调函数,并尝试理解何时应该使用它们。

MDN Web 文档提供了以下示例:

function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('Please enter your name.');
  callback(name);
}

processUserInput(greeting);

然而,我很难看出这比以下方式更有益,其中我没有将问候函数作为参数传递?
function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput() {
  var name = prompt('Please enter your name.');
  greeting(name);
}

processUserInput();

1
更易于测试,耦合度更低,更接近单一职责原则的理想。 - Ben Aston
因为您还可以传递一个执行除了弹出名称之外的其他操作的函数,例如将名称记录到控制台。 - user184994
如果你想在得到他们的名字后警告其他内容怎么办? - George
1
该示例的目的是极其简单,以便您可以了解它的工作原理。它并不意味着要展示回调函数的有用性。 - Quentin
@George,这不是在我的第二个例子中的问候(name)之后,以及在第一个例子中的回调(name)之后可以实现吗?我读了一篇很长的文章,其中有一些复杂的回调,但我正在努力理解它们通常应该在什么时候使用。感谢您的回复,我会阅读您所有的观点。 - paddyfields
@paddyfields 这取决于情况,如果你在其他地方定义了 processUserInput 以供不同页面使用呢? - George
4个回答

6
由于JavaScript是异步的,有时候很难处理非阻塞函数的响应。例如,如果您正在进行ajax调用,则将以异步方式执行,并且结果将在稍后返回。但是在这段时间内,主执行流程将通过ajax代码并开始执行以下语句,在这种情况下,很难捕获响应以进一步处理。
为了处理这些情况,回调函数出现了。您可以将一个函数作为参数传递给ajax函数,一旦响应返回,就通过传递响应数据作为参数来调用回调函数以进一步处理。
更多信息请参见:http://callbackhell.com/

3
简单来说,回调是一种提前询问问题(或请求任务)的方式,即在完成某项任务后执行另一项任务(通常是带有结果的)。整个目的是为了暂时保留需要稍后完成的函数,通常是因为现在没有必要的输入。你的实现与MDN的主要区别在于,你的实现更难维护和推理,因此测试起来更困难。
1. 维护/重用
假设你已经写了几千行代码,然后需要更改processUserInput()函数的功能。更改或编写一个新的回调函数比更改processUserInput()函数要容易得多。如果processUserInput()函数更加复杂,则情况会更明显。这也意味着MDN的实现在各种场景下都更加有用,而你的实现则不然。你可以通过编写不同的回调函数来将其重用于不同的情况,例如说再见、大写名字等等,然后将它们插入到processUserInput()中。
2. 测试/更容易推理
MDN的实现更容易理解。假设processUserInput(greeting)函数可能返回一个问候语,比假设processUserInput()函数做什么更容易。这使得测试更容易,因为你始终可以确定给定输入,MDN的实现将始终返回相同的输出。

1
回调函数在特定情况下非常有用,例如,在使用JavaScript开发Google Chrome浏览器扩展时,一旦设置完成,可以使用回调来拦截Web请求。

回调的目的是在触发事件(某种事件)时执行回调例程。通常,功能遵循链接API的接口。通过实现回调支持,您可以在操作的某个阶段重定向执行流程。对于第三方开发人员而言,回调在处理他人库时非常有用,具体取决于他们要做什么。将它们视为通知系统。

一般而言,带参数的函数对于灵活性和维护性非常有用。如果您为不同的事物使用不同的函数,则这些函数可以简单地反复使用以提供不同的功能 - 同时仍然防止源代码膨胀并且重复了很多次几乎相同的代码。同时,如果您将函数用于自己的库,并出现错误,则可以简单地修补一个函数,然后问题就解决了。

在您的示例中,您将回调函数传递给要调用的函数 - 要调用的函数将调用回调函数并传递正确的参数。这是灵活的,因为它允许您具有用于打印变量内容的回调例程,用于计算传入字符串长度的回调例程,或用于在其他位置记录它的回调例程等。它允许您重复使用设置的功能,并使用正确的参数调用不同的函数,而无需重新制作原始函数。

-2

这个例子不适合理解回调函数

简单来说,回调函数是在某些事件、函数或表达式之后或响应时使用的。也就是说,当父函数完成执行后,回调函数会被执行。

简单示例:

function hungerStatus(status,cb){
    return cb(status)
}
function whatToDo(status){
    return status ? "order Pizza" : "lets play"
}

hungerStatus(false,whatToDo)

另一个例子

// global variable​var allUserData = [];
​
​// generic logStuff function that prints to console​function logStuff (userData) {
    if ( typeof userData === "string")
    {
        console.log(userData);
    }
    else if ( typeof userData === "object")
    {
        for (var item in userData) {
            console.log(item + ": " + userData[item]);
        }
​
    }
​
}
​
​// A function that takes two parameters, the last one a callback function​function getInput (options, callback) {
    allUserData.push (options);
    callback (options);
​
}
​
​// When we call the getInput function, we pass logStuff as a parameter.​// So logStuff will be the function that will called back (or executed) inside the getInput function​
getInput ({name:"Rich", speciality:"JavaScript"}, logStuff);

请参考回调函数解释


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接