前言
在JavaScript中Callback是最基础的也使最常用来处理非同步的方式,而callback是什么?简单来说就是在另一个函数完成执行之后执行就称为callback
,而複杂来说由于JavaScript中的函数属于一级成员,代表着函数可以作为参数传递并且可以由其他函数返回,而作为参数传递的任何函数都称为callback function
,使用callback function虽然可以解决非同步的问题,但是他同时也有许多缺点,本章终将仔细地介绍callback function的缺点。
Why do we need Callback Functions?
在介绍callback的缺点之前,让我们再複习一次倒底JavaScript为什么会需要一个callback function,由于JavaScript是个由上而下运行的程式但是某些情况下会需要使用非同步的方式运行,而callback function可以确保他在我们指定的任务完成之前不会被运行,但当我们指定的任务完成时他会立刻运行
,这使我们在开发非同步程式的时候能够确保我们的流程顺序不会有错误。
让我们举个例子,当我们开发了一个专案,我们需要使用ajax获得后端的数据再将它显示出来,我们需要保证我们确实拿到了后端的资料(ajax已经完成)后才将它显示出来不然会发生错误,这样的情况下使用callback function就能够确保我们的时间顺序,不会在ajax任务尚未完成之前就将data显示。
ajax("https:ajax.com", function(data){ console.log(data);})
What is callback funciton Disadvantages?
我们了解了callback function最初被设计出来是为了要解决什么问题,他确实能够在我们处理非同步事件的时候起到一的很好的作用,但是他确实也有需多缺点,让我们一一介绍他有哪一些缺点:
Order problem
当我们在阅读别人的程式的时候,由于我们习惯由上而下的阅读所以对于非同步的程式来说我们会看得稍微有点吃力,让我们举个例子:
// a...setTimeout(function(){ // c...},1000);// b
当我们要将上面这个程式解释给一个JS新手时,我们该如何解释他?
可能会有人说:先做a,设置一个等待一秒的定时器,一秒过后执行c。也可能会说:先做a,设置一个等待一秒的定时再去做b,一秒过后再回来做c。虽然第二种说法比较正确,但是说实在的如果我是一个JS新手估计我会完全不知道你在说什么,为什么程式执行到下面后又跳回上面?这样的问题出现在许多开发人员心中。
你可能觉得:这样就不行了也太弱了吧...那是因为我们只介绍了简单的callback问题,让我们再来一个更难的:
doA(function(){ doB(); doC(function(){ doD(); }) doE();});doF();
看到上面的程式估计已经晕的,如果是一个新手来看这个程式我想他已经在放弃的路上了,这个程式的真实发生顺序:doA -> doF() -> doB() -> doC() -> doE() -> doD()
。
当我们在追蹤这种非同步事件的程式时,常常会因为使用callback function导致我们我需要再一个程式中不断上上下下的去看执行的顺序,这对于日后维护或是其他人来看都会是一个不便的事情。
Callback Hell
使用callback function除了会让阅读程式因为顺序问题不断上上下下增加阅读难度之外,还有一个在JavaScript中流传已久的callback hell,让我们来举个例子实际体验一下地狱:
listen('click', function handler(event){ setTimeout(function request(){ ajax('https://some.url.1'm function responde(test){ if(test === 'hello'){ handler(); } else { request(); } }) })})
由于JS中函数属于一级公民可以作为参数传递,所以就会有这种多重嵌套的问题,我们来分析一下上面程式:
首先我们先注册一个监听事件listen('click', function handlet(event){ // ...})
当发生监听事件时触发计时器在500ms之后触发callback functionsetTimeout(function request(){ // ...})
计时结束后触发callback function ajax进行数据请求ajax('https://some.url.1'm function responde(test){ // ...})
当获得ajax数据后再对数据进行判断if(test === 'hello'){ handler();} else { request();}
当看完这些程式逻辑后估计已经头晕了,不过这只是简单的三个嵌套,还有更恐怖的...
结论
callback function是JS中处理非同步的基础,但是随着JS的成熟与更加庞大的需求它们对于非同步编程的演化趋势来讲显得不够。
我们对于阅读程式会习惯由上到下的同步化、顺序化阅读而如果使用callback function会因为执行顺序的问题导致程式上上下下的执行,对后续的维护与阅读造成很大的困扰,并且若嵌套多层callback function则这个问题更加明显。
参考文献
You Don't Know JavaScript
JavaScript: What the heck is a Callback?
JavaScript Callback Functions – What are Callbacks in JS and How to Use Them