← 返回首页
深入理解回调函数
发表时间:2022-08-24 18:54:50
深入理解回调函数

前端面试中最容易被问到的问题就是什么是回调函数?回调函数的意义?通过本文咱们彻底搞懂什么是回调函数。

1.什么是回调函数?

最通俗的解释就是:回调函数就是把这个函数当做参数传给另一个函数,在另一个函数里面通过这个函数参数去调用这个函数,这个过程称为回调。而那个当成参数的函数就是回调函数。

看下面代码:


//另一个函数
function test(callback){
    console.log('test() start....')
    callback(); //这里是回调
    console.log('test() end....');
}

//定义回调函数
function fn(){
    console.log('我是回调函数...')
}

test(fn);

运行结果:

test() start....
我是回调函数...
test() end....

这里fn函数就是回调函数。之所以称为回调函数,是因为在另一个函数中调用完回调函数后会立刻返回主函数(这里的主函数就是test函数)继续执行,所以很形象的称之为回调函数,英文名字:callback.

注意:执行回调函数后是立即返回,这里的立即返回就是不会等待回调函数的执行结果,立刻返回主函数执行后面的代码。

把上面的代码改写如下:

function test(callback){
    console.log('test() start....')
    callback();
    console.log('test() end....');
}

function fn(){
   setTimeout(()=>console.log('我是回调函数...'),1000)
}

test(fn);

运行结果:

test() start....
test() end....
我是回调函数... 

因为setTimeout本身就是异步操作。所以在调用完回调函数后,会立刻执行完主函数的代码。

其实setTimeout本身就执行了回调函数,可以说setTimeout是各位小伙伴最早接触的回调函数了,我们看看setTimeout的定义。

setTimeout(callback, delay)

到此,关于回调函数的概念咱们总结以下两点:

1). 回调函数一定是把自己当做参数传递给另一个函数,在另一个函数中调用。如果单独调用这个函数那么它就不是回调函数。

2). 回调函数调用后会立刻返回执行主函数的代码,不会等待回调函数的执行结果。

2.回调函数的意义?

好奇的小伙伴肯定会问: 我们为什么不直接在test函数中,直接调用fn()方法呢?为啥非要把fn当做参数传递给test然后在test中调用呢?

上面的代码改写如下:

function test(){
    console.log('test() start....')
    fn();
    console.log('test() end....');
}

function fn(){
   setTimeout(()=>console.log('我是回调函数...'),1000)
}

test(fn);

运行结果:

test() start....
test() end....
我是回调函数... 

既然运行结果完全一样,咱们使用回调函数的意义是什么呢?

回调函数的意义在于:通常test函数我们可以理解为是系统内部的代码,换句话说就是系统开发定义好的,咱们程序员看不到这段代码,也不允许你修改这段代码。但是系统内部又想提供一种机制允许执行外部用户自己写的代码,那么就可以使用回调函数。这样做的好处是:通过回调函数用户的程序逻辑可以传递给系统内部,系统内部调用完回调函数,还可以把结果反馈给用户程序。

3.回调函数传递参数

主函数在执行回调函数时,可以传参,这个回调函数就可以获得主函数传递过来的参数值。

function test(callback){
    console.log('test() start....')
    fn('你好回调函数...');
    console.log('test() end....');
}

function fn(resp){
    console.log(resp);
}

test(fn);

运行结果:

test() start....
你好回调函数...
test() end....

上面的例子是主函数给回调函数传参,当然回调函数也可以给主函数传参。

function test(callback,resp){
    console.log('test() start....')
    console.log(resp)
    fn('你好回调函数...');
    console.log('test() end....');
}

function fn(resp){
    console.log(resp);
}

test(fn,'helloworld');

运行结果:

test() start.... 
helloworld       
你好回调函数...  
test() end....   

回调函数传参另一个重要意义在于,如果主函数中执行一些异步操作,我们如何把这个异步操作的结果返回呢?看下面代码:

function test(){
  setTimeout(()=>{
      return{
          username: 'zhangsan'
      }
  },2000)
}


let resp = test();
console.log(resp);

运行结果:

undefined

因为在我们调用完test()后就已经获得函数的返回值了,两秒钟后再返回已经不赶趟了,这就很尴尬了。 这时候回调函数就派上用场了。

function test(callback){
  setTimeout(()=>{
      callback({username: 'zhangsan'})
  },2000)
}

function fn(resp){
    console.log(resp);
}

test(fn);

运行结果:

{ username: 'zhangsan' } 

4.Java语言能实现回调函数吗?

回调函数是一种编程思想,与语言无关;回调函数的核心就是将函数的指针(或者引用)传递给其他函数,让其他函数在特定的时候,通过指针(或者引用)调用该回调函数。

以下是Java实现回调的例子。

//函数式接口用来创建函数引用。
interface Callback {
    void success();
}

class FutureCallback implements Callback {
    @Override
    public void success() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("do success");
    }
}

public class CallabackDemo {

    private Callback callback;
    public CallabackDemo(Callback callback) {
        this.callback = callback;
    }

    public void doSomething(){
        System.out.println("do something start...");
        new Thread(() -> callback.success()).start();
        System.out.println("do something end...");
    }

    public static void main(String[] args) {
        Callback callback = new FutureCallback();
        new CallabackDemo(callback).doSomething();
    }
}

运行结果:

do something start...
do something end...
do success

小结:

1).回调函数就是把这个函数当做参数传给另一个函数,在另一个函数里面通过这个函数参数去调用这个函数,那么当成参数的函数就是回调函数。 2).回调函数的意义是允许系统内部代码通过回调函数执行用户代码。 3).通过回调函数可以获得一个异步操作的返回值。