转载自瓶子君的blog 链接
step1:回调函数callback
1 | asyncFunction(function(value) { |
这种回调函数,大家是最熟悉的。一般是需要在某个耗时操作之后执行某个回调函数。
例如:
1 | setTimeout(function() { |
其中,我们称setTimeout
为发起函数,fn
为回调函数。都是在主线程上调用的,其中发起函数用来发动异步过程,回调函数用来处理结果。在执行setTimeout
1s后,执行function函数。
下面,我们再看一种情况。
1 | $.ajax({ |
在上例中,我们看到这段回调函数,不断的在回调,这只是三层回调,在实际应用中,我们遇到的需求会更复杂,回调也许更多,调试起来也就更麻烦,代码也更不美观,这就是我们要引入的第一个问题:回调地狱。
问题1: 回调地狱
回调地狱是JS里一个约定俗成的名称,一般情况下,一个业务依赖于上层业务,上层业务又依赖于更上一层的业务,以此类推,如果我们使用回调函数来处理异步的话,就会出现回调地狱。
主要是因为:大脑对业务的逻辑处理是线性的、阻塞的、单线程的,但是回调表达异步的方式是非线形的、非顺序的,这使得正确推导这类代码的难度很大,很容易出bug。
再例如:
1 | // A |
A和B发生于现在,在JavaScript主程序的直接控制之下,而C会延迟到将来发生,并且是在第三方的控制下,在本例中就是函数$.ajax(…)。从根本上来说,这种控制的转移通常不会给程序带来很多问题。
但是,请不要被这个小概率迷惑而认为这种控制切换不是什么大问题。实际上,这是回调驱动设计最严重(也是最微妙)的问题。它以这样一个思路为中心:有时候ajax(…),也就是你交付回调函数的第三方不是你编写的代码,也不在你的直接控制之下,它是某个第三方提供的工具。
这种情况称为控制反转,也就是把自己程序一部分的执行控制交给某个第三方,在你的代码和第三方工具直接有一份并没有明确表达的契约。
既然是无法控制的第三方在执行你的回调函数,那么就有可能存在以下问题,当然通常情况下是不会发生的:
- 调用回调过早
- 调用回调过晚
- 调用回调次数太多或者太少
- 未能把所需的参数成功传给你的回调函数
- 吞掉可能出现的错误或异常
- ……
这种控制反转会导致信任链的完全断裂,如果你没有采取行动来解决这些控制反转导致的信任问题,那么你的代码已经有了隐藏的Bug,尽管我们大多数人都没有这样做。
这里,我们引出了回调函数处理异步的第二个问题:控制反转。
step2:控制反转
综上,回调函数处理异步流程存在2个问题:
1. 缺乏顺序性: 回调地狱导致的调试困难,和大脑的思维方式不符
2. 缺乏可信任性: 控制反转导致的一系列信任问题
那么如何来解决这两个问题,先驱者们开始了探索之路……
参考:
瓶子君 blog
- 本文标题:浏览器异步(二)
- 本文作者:Jonnzer
- 创建时间:2020-07-18 00:37:05
- 本文链接:https://jonnzer.github.io/2020/07/18/JS/浏览器异步(二)/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!