Callback

646 阅读2分钟

Knowledge Base

什么是回调函数?

把函数作为参数传进另一个函数中,这就是回调函数。

为什么需要用到回调函数?

JavaScript是事件驱动语言,其运行机制如图下,在执行栈中,主线程有两个分支:同步任务和异步任务。可以看出一般我们解决异步事件都是用回调函数去处理。

​Code

同步(阻塞)中的回调函数实例

  1. 例如单击按钮事件。
    <body>
        <input type="button" value="click me 1" onclick="clickEvent()"/>
        <button id="btn">click me 2</button>
    </body>
    <script>
        //由于无法知道用户何时会点击按钮,所以事件就委托给按钮,当按钮被点击之后,事件(回调)就会执行
        function clickEvent() {
            alert("This is a callback function");
        }
        
        var button = document.getElementById('btn');
        button.addEventListener('click', function(e) {  //匿名回调函数
            alert("This is a anonymous callback function");
        });
    </script>
  2. 在sumTwo() 执行完成后执行output()。

        function sumTwo(a, b, callback) {
            var sum = a + b;
            (callback && typeof(callback) === "function") && callback(sum);
        }
        
        function output(sum) {
            //callback函数负责将结果输出
            alert(sum);
        }
    
        sumTwo(1, 2, output);

异步中的回调函数实例

  1. Ajax异步请求线程
    let requestURL = 'www.'
    $.ajax({
        url:requestURL,
        dataType:json,
        success:(data) => {
            //箭头函数回调
            console.log('request successfully');
        },
        error:() => {
            console.log("something wrong")
        }
    })
    
    console.log('代码执行结束');
    
    
    /*
    **Execution Steps
    **1.声明一个变量
    **2.给后端发送API请求,注册success回调/error回调,注意!还没有执行success回调/error回调
    **3.执行console.log('代码执行结束')
    **4.主线程执行完以上3步,若API请求成功,把success回调放在消息队列里面,等待主线程空闲才执行;若API请求失败,把error回调放在消息队列里面,等待主线程空闲才执行。
    */
  2. setTimeout模拟异步请求
        function asynSimulation() {
            setTimeout(function() {
                console.log("asyn callback")
            },0);
        }
        
        asynSimulation();
        console.log("代码执行结束");
    
    
    /*
    **Execution Steps
    **1.执行asynSimulation(), 注册setTimeout匿名回调。
    **2.setTimeout运行机制提到,必须要等到当前脚本的同步任务和“任务队列”中已有的事件,才会执行setTimeout指定的任务,所以先执行console.log("代码执行结束");
    **3.执行setTimeout匿名回调
    */
  3. promise异步编程,解决回调地狱问题

        var getJson = function(url) {
            //new Promise,马上执行代码
            var promise =  new Promise(function(resolve, reject) {
                var client = new XMLHttpRequest();
                client.open('GET', url);
                client.onreadystatechange =  handler;
                client.responseType = "json";
                client.setRequestHeader("Accept", "application/json");
                client.send();
    
                function handler() {
                    if(this.readyState !== 4) {
                        return;
                    }
                    if(this.status === 200) {
                        resolve(this.response);
                    } else {
                        reject(new Error(this.statusText));
                    }
                }
            })
            return promise;
        }
    
        getJson('/posts.json').then(function(json) {
            console.log(json);
        }, function(error) {
            console.log(error)
        })
    
    /*
    **Execution Steps
    **1.执行getJson()
    **2.执行成功,调用resolve();执行失败,调用reject()
    */