回调函数的那些事

    技术2022-07-11  87

    回调函数

    这只是一个称呼,表达的含义是 将函数A作为函数B的参数,并且函数A在函数B内进行调用。

    这可以用来解决异步。因为异步的时候我们不能一直等待,因此需要一个函数来在异步操作执行完了以后,继续接下来的顺序操作。

    举例:

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <p>点击按钮,3 秒后会弹出 "Hello"。</p> <button onclick="myFunction()">点我</button> <script> var myVar; function myFunction() { myVar = setTimeout(alertFunc, 3000); } function alertFunc() { alert("Hello!"); } </script> </body> </html>

    在这个例子中,点击按钮“点我”,会触发myFunction函数,函数中有一个异步函数,settimeout,其中传递了自定义的回调函数alertFunc。

    解释一下: settimeout是一个封装好的函数,给我们暴露一个参数接口,传递自定义的回调函数。

    同时,这个回调函数在调用的时候可能要进行一定传参。

    同时对回调函数传参有两种方式:

    将回调函数的参数作为与回调函数同等级的参数进行传递

    回调函数的参数在调用回调函数内部创建

    相信以上描述已经让大家明白了回调函数的使用。那么,接下来,让我们讨论一下令人诟病已久的回调地狱和它的解决方法吧。

    首先,文字解释一下回调地狱,即:多次连续异步操作造成不停写入回调函数,而导致代码的可读性和维护性变差。

    举个例子:

    var fs = require('fs'); fs.readFile('./views/index.html', (err, data) => { if (err) { throw err } fs.readFile('./views/main.html', (err, data) => { if (err) { throw err } fs.readFile('./views/update.html', (err, data) => { if (err) { throw err } console.log(data.toString()); }) console.log(data.toString()); }) console.log(data.toString()); })

    为了保证顺序,依次执行三个异步操作。每个一步操作都有一个回调函数。

    如果我不进行说明,这个代码的可读性是不是很差呢?

    那么,有没有什么办法能够改进这种形式呢?

    既然回调函数是在异步操作执行完再进行调用,那我们能不能按照这个逻辑,把代码写成“顺序执行的呢?1、2、3”这样。

    ok,那接下来我们引入,promise的概念:

    promise代表一个异步操作;通过promise进行异步操作,异步操作完成之后,通过resolve函数,promise从pending变成fulfilled状态,并抵达then方法。如果操作失败,通过reject函数,promise从pending变成rejected。

    其中涉及到promise原理部分,推荐几个阅读材料:

    这个带着我了解了promise的底层思想。resolve和reject作为一个函数是怎么改变promise状态的。

    then又是怎么进行处理的。

    https://www.jianshu.com/p/43de678e918a

    这是一个英文的promise的介绍,感觉可以一看。

    http://www.mattgreer.org/articles/promises-in-wicked-detail/

    https://www.promisejs.org/

    那么async和await又是用来做什么的呢?

    他也是用来解决异步编程的,大家称之为“最终解决方案”

    单纯的写回调函数,很容易形成回调地狱。因此我们提出了promise,通过then和catch来处理成功或失败之后的结果。 但是通过then去解决回调链,依旧有点难度。能否用同步代码的形式去写异步的操作?

    这就是async、await大杀器。

    通过async关键字声明函数内部存在异步操作。通过await声明异步操作。

    其成熟的解释在:

    https://segmentfault.com/a/1190000007535316

    Processed: 0.010, SQL: 9