函数在 javascript 中可以作为参数或作为返回值,在异步编程中回调函数被大量使用,当回调函数被调用,说明满足了某个触发条件,有时还会包含结果,提供更多的细节。回调函数可能会出现回调地狱现象,可以利用 promise 对象解决该问题。
回调函数
小明在奶茶店点了奶茶,店员开始制作奶茶,此时“制作奶茶”与“小明等待奶茶”是一个同时进行的不同的两个事件(任务),那么,小明获取店员制作成功的奶茶是从“制作奶茶”这一事件获取的结果,所以小明才能够完成“购买奶茶”这一事件。如果,小明在“购买奶茶”这一事件中,不想一直等待而是想去做一些其他的事情,比如购买冰淇淋。
现在,我们将这一案例抽取为一个个事件,用 javascript 函数体现出来:
目前,这些事件属于同步任务(事件),它们被主线程由上到下依次执行,无法在同一时间内执行多个事件。你会发现,这些事件之间是各自独立的。如何将它们有机地、有序地结合在一起是一个问题。
因此,在 javascript 中,有一种解决方式叫做异步任务(事件),利用回调函数将这些独立的事件结合在一起。在 javascript 中,函数作为第一等公民的存在,可以将函数作为对象传递给方法作为实参进行调用,即回调函数。
请转至“[js]函数作为值”一文,了解什么函数是如何作为值,并且可以作为函数实参进行传递以及调用的。
回调函数的确将这些独立事件有机地结合在一起了,但是随之而来的就是回调地狱。
现在,我们明白了回调函数的好处。再列举一个例子,深入了解回调函数的好处在哪。若实现一个简单的计算器,其功能有加、减、乘、除等运算,通常情况下会想到一个函数获得两个参数,并将运算类型作为字符串传递给函数参数以实现不同需求。
上述代码,存在一个明显的问题。如果在减法中做其他的限制条件(或增加源代码的功能),它会影响到整个 calculate 函数本身。再者,如果我扩展 calculate 函数功能,它也会影响到函数本身。对于这种情况,我们寄希望于回调函数,通过它来解决这个问题。
现在,调用 calculate 函数时,可以在回调函数中做一些附加限制条件,它不会影响到 calculate 这个函数本体。并且,回调函数可以从 calculate 函数本体中获取更多的细节(信息),通过这些信息我们又能做出更多的操作。
在回调函数中不同的排序方式可以决定最后的结果。回调函数使得程序更加灵活。
回调地狱
在上面的“小明买奶茶”案例中,回调内部再嵌套回调,其代码形状上看着像180°旋转之后的金字塔,这种层层嵌套就是回调地狱。
因此,promise 可以解决回调地狱的问题。promise 是一个对象,用于表示一个异步操作的最终完成(或失败)及其结果值。
利用 promise 解决“小明买奶茶”回调地狱:
在代码层面,使用 promise 之后,解决了多层回调函数调用导致的“金字塔”现象。让我们看看实现效果:
请转至 mdn 关于 promise 的解释:promise - javascript | mdn