欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

回调函数及异步编程理解(一)

程序员文章站 2022-05-08 11:29:32
...

回调函数:

这只是一个称呼,表达的含义是 将函数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是一个封装好的函数,给我们暴露一个参数接口,传递自定义的回调函数。

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

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

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

    回调函数及异步编程理解(一)

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

    回调函数及异步编程理解(一)

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

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

举个例子:

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原理部分,推荐几个阅读材料:

  1. 这个带着我了解了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