回调函数与回调地狱及其解决方法 | JavaScript

JavaScript中的回调函数与回调地狱及其解决方法

以下为整理的思维导图 图片版+文字版
文末附有参考文章链接


知识点思维导图版

一、什么是回调函数

1.MDN的定义

回调函数是作为参数传给另一个函数的函数,然后通过在外部函数内部调用该回调函数以完成某种操作。

2.其他文章的解释定义

回调函数是一个函数,将会在另一个函数完成执行后立即执行。回调函数是一个作为参数传给另一个 JavaScript 函数的函数。这个回调函数会在传给的函数内部执行。

3.补充:回调函数和异步的关系

  • 回调函数不完全等于异步
  • 本质上说,回调函数是异步的
  • 异步是指JS代码的执行顺序,为了解决JS单线程可能导致阻塞的情况,必须编写异步代码
  • 回调可以理解为一种业务逻辑,回调函数是异步操作的一种基本方法

二、为什么需要回调函数

1.JS单线程可能导致的情况

如果在队列中有一件事情需要花费很多的时间,那么后面的任务都将处于一种等待状态,有时甚至会出现浏览器假死现象。

2.引入JS异步机制

  • 每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

  • 在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,异步模式甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降。

  • 与之相对应的概念是“同步任务”,同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。

3.回调函数的作用

  • 回调函数是异步编程最基本的方法,其优点是简单、容易理解和部署。
  • 回调函数最大的缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling)

三、怎样避免回调地狱

1.回调地狱是什么

  • 回调函数的层层嵌套,就叫做回调地狱。回调地狱会造成代码可复用性不强,可阅读性差,可维护性(迭代性差),扩展性差等问题。
  • 回调地狱的原因是,当人们试图以一种从上到下的视觉方式执行JS的方式编写JS,期望第1行发生的任何事情都会在第2行的代码开始运行之前完成,而代码的实际执行则事与愿违。
  • 回调地狱的本质:①嵌套函数存在严重的耦合,牵一发而动全身。②错误处理比较艰难,不能使用try catch 和不能直接return。

2.怎样避免回调地狱

1.保持代码简短简洁,例如函数命名清晰

2.模块化

3.Promise

a.基本概念
  • Promise本身只是一个容器,真正异步的是它的两个回调resolve()和reject()
  • Promise本质 不是控制 异步代码的执行顺序(无法控制) , 而是控制异步代码结果处理的顺序
  • Promise对象有三个状态:pending(进行中),fulfilled(已成功),rejected(已失败)
b.使用Promise解决回调地狱

思路

  • (1)promise创建时,里面的代码还是异步无序操作
  • (2)promise的原理是,利用then方法将异步操作的结果,按照顺序执行,catch方法用来接收处理失败时相应的数据。在上一个promise的then方法中,返回下一个promise对象
    总结:不要在创建promise的时候去处理异步操作结果,而应该通过 then() 方法来处理

(以下代码来自文章《什么是回调地狱,如何用Promise解决回调地狱,看完这篇你就明白了》文末有链接)

回调函数与回调地狱及其解决方法 | JavaScript_第1张图片回调函数与回调地狱及其解决方法 | JavaScript_第2张图片

c.Promise的优缺点

优点

  • (1)避免了回调地狱,用同步的方式写异步的代码
  • (2)控制异步操作更容易,Promise对象提供了统一的接口
  • (3)链式操作,可以在then中继续写Promise对象并返回,然后继续调用then来进行回调操作

缺点

  • (1)then的链式调⽤也会带来额外的阅读负担,不易读
  • (2)Promise对象一旦新建就会立即执行,无法中途取消
  • (3)若不设置回调函数,Promise内部会抛出错误,不会流到外部
  • (4)当处于pending状态时,无法得知当前处于哪一阶段

4.async/await

a.基本概念
  • async/await是 Generator 函数的语法糖,也就是处理异步操作的另一种高级写法
  • async/await是基于Promise实现的,它不能用于普通的回调函数
b.使用async/await解决回调地狱
  • async声明function是一个异步函数,返回一个promise对象,可以使用 then 方法添加回调函数。
  • async函数内部return语句返回的值,会成为then方法回调函数的参数。

(以下代码来自文章《什么是回调地狱,如何用Promise解决回调地狱,看完这篇你就明白了》文末有链接)
回调函数与回调地狱及其解决方法 | JavaScript_第3张图片回调函数与回调地狱及其解决方法 | JavaScript_第4张图片

c.async/awit的优缺点

优点

  • (1)内置执行器, Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器,也就是说,async 函数的执行,与普通函数一模一样,只要一行。
  • (2)语义更清晰,与* 和 yield相比,async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果
  • (3)适用性更广,co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
    缺点
  • 滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性

参考文章链接:

1.什么是回调地狱,如何用Promise解决回调地狱,看完这篇你就明白了 (参考了回调地狱的解决方法)
2.深入理解 JavaScript 回调函数 (参考了回调函数的概念、回调函数和异步的关系)
3.「硬核JS」深入了解异步解决方案 (参考了异步模式的概念、回调函数的优缺点和async的优缺点)
4.回调地狱(参考了回调地狱的原因)
5.JS 异步编程六种方案 (参考了回调函数和异步的关系)
6.解决回调函数带来的回调地狱(参考了回调函数的作用和回调地狱的概念)
7.JS 异步编程六种方案(参考了async/await的相关阐述)
8.async/await 优雅永不过时(参考了async/await的相关理解)

你可能感兴趣的:(JavaScript笔记,javascript,前端)