为什么要使用回调函数而不是直接调用它们?

4

我正在阅读有关回调函数的内容(此处)(也是我参加的在线课程中的一部分),现在我卡住了。原因是我不能理解为什么需要使用回调函数,如果可以直接调用它们。以下是示例:

1 - 使用回调函数:

    function showArticle(id, callbackSuccess, callbackError){
        
        if (true){
            callbackSuccess("This is a callback function", "It is very utilized.");
        } else {
            callbackError("Error on data recovery.");
        }

    }

    var callbackSuccess = function(title, description){
        document.write("<h1>" + title + "</h1>");
        document.write("<hr>");
        document.write("<p>" + description + "</p>");
    }

    var callbackError = function(error){
        document.write("<p><b>Erro:</b>" + error + "</p>");
    }

    showArticle(1, callbackSuccess, callbackError);

2 - 这是我没有使用回调函数并且结果相同的代码:

    function showArticle(id){
        
        if (true){
            callbackSuccess("This is a callback function", "It is very utilized.");
        } else {
            callbackError("Error on data recovery.");
        }

    }

    var callbackSuccess = function(title, description){
        document.write("<h1>" + title + "</h1>");
        document.write("<hr>");
        document.write("<p>" + description + "</p>");
    }

    var callbackError = function(error){
        document.write("<p><b>Erro:</b>" + error + "</p>");
    }

    showArticle(1);

为什么我应该使用回调函数而不是在示例2中直接调用它们?

3个回答

6
你说得对,在你所给出的例子中,回调函数没有任何意义,但是这并不是回调函数通常的使用方式。
通常情况下,回调函数用于:
  1. 迭代、映射或筛选函数中,它们会为数组、列表或其他容器中的每个元素调用你的回调函数
  2. 执行异步工作的函数中,当工作成功完成、失败或两者都有(取决于您调用的 API 的风格)时,会调用你的回调函数
  3. 接受回调函数参数的函数,当某些事情发生或者可能发生时调用这些回调函数,例如 DOM 元素上的 click 事件处理程序
...但是还有其他类型的回调函数。
数组的 filter 函数就是第一种情况的一个例子:它为数组中的每个条目调用回调函数,并使用回调函数的返回值来判断该条目是否应该在它返回的新的筛选后的数组中。

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const odds = numbers.filter(num => {
    console.log(`callback called with ${num}`); // logs 10 times
    return num % 2;
});
console.log(odds); // [1, 3, 5, 7, 9]

Promise方法中的thencatchfinally是#2的示例。假设我们有一个返回Promise的startSomethingAsynchronous函数。下面是如何设置fulfillment和rejection处理程序(回调):

startSomethingAsynchronous()                // Starts an asynchronous process
.then(result => {                           // <−+
    // ...do something with the result...   //   +− This is a fulfillment handler
})                                          // <−+
.catch(error => {                           // <−+
    // ...report or handle error...         //   +− This is a rejection handler
});                                         // <−+

如果从startSomethingAsynchronous()返回的承诺被兑现(成功完成),则会调用兑现处理器。如果该承诺被拒绝(失败),或者该承诺被兑现但由then返回的承诺被拒绝(例如,因为兑现处理器发生错误),则会调用拒绝处理器。(像这样链接事物是相当常见的,但还有许多其他使用承诺的方法,这只是一个例子。)

在DOM中,addEventListener函数是第3种示例:

document.querySelector("input[type=button]")
    .addEventListener("click", function() {
        console.log("Clicked!"); // logs as many times as you click the button
    });
<input type="button" value="Click Me">


2
JavaScript按顺序从上到下运行代码。但是,有些情况下代码在发生某些事件后运行(或必须运行),而且不是按顺序运行的。这就是所谓的异步编程。
回调函数确保在任务完成后才会运行函数,而不是在任务未完成时运行函数。它帮助我们开发异步JavaScript代码,并使我们免受问题和错误的影响。
在JavaScript中,创建回调函数的方法是将其作为参数传递给另一个函数,然后在某些事件发生或某个任务完成后立即回调它。
你可以在这里阅读更多内容。

2

以上答案都是正确的。我的回答只是其中一个原因(异步性质)的简化。

请注意并非所有操作都是顺序执行的。

  • 调用数据库可能需要100毫秒、200毫秒或1秒才能返回数据。
  • 读取未知大小的文件可能需要X秒。

在您不知道操作需要多长时间的情况下,使用回调方法,这是JavaScript的特性

有些语言会阻塞流程(我将等待对数据库的调用),或者创建线程(我将在另一个“进程”中执行这些操作)。

JS将采用Promises和callbacks。


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