什么是回调地狱?
PS: 某大牛说过,世上本没有多层回调嵌套,写的人多了也便有了。
下面我们举个例子
在使用jquery animat做多个动画效果的时候,可能很多的童鞋写出过如下的代码。
代码如下 | 复制代码 |
// 在前一个动画执行完成后,紧接着执行下一个动画 $('xx').animate({xxxx}, function(){ $('xx').animate({xx},function(){ //do something },1000) },1000) |
由上面的代码可以看出,目前有2层的回调嵌套。
那我们思考下,如果我们有3个,4个或是更多的动画效果要紧接着执行,
我们是不是就发现,我陷入了无尽的回调地狱里去了呢?
可以访问这里看看我们平常会写出的一些回调 更多例子:js代码中的回调地狱
那么,到这里,大家看到了,大量的回调函数嵌套,
不仅仅让代码显得更加难看、臃肿,也让项目变得越来越不好维护。
所以,我们要想办法来避免这样子的代码出现在我们的项目中。
异步编程带来的好处和烦恼
javascript引擎是单线程的 但是借助异步编程,使得服务器端运行的NodeJs具备了高性能。
也具备了IO操作并行执行能力,这也使得很多童鞋可能写出很多回调嵌套的代码。
让我们的代码变得难看了。当然,这不是js语言本身的问题,就像开头写的:
世上本没有多层回调嵌套,写的人多了也便有了。
使用Promise来解决回调地狱问题
Promise是什么?
Promise是一种抽象对象。CommonJS定义了Promises/A规范。
如果想要具体了解点这里: 详细了解Promise是什么
Promise模式在任何时刻都处于以下三种状态之一:
未完成(unfulfilled)
已完成(resolved)
拒绝(rejected)。
在jquery的1.5以上版本的ajax就是基于promise实现的。 所以我们可以使用如下方式实现ajax请求:
代码如下 | 复制代码 |
$.when( |
如何实现一个Promise
接下来我们来实现一个Promise,我们就暂且称他为Deferred(跟jquery里保持一致)
代码如下 | 复制代码 |
function Deferred() { Deferred.prototype.done = function(cb){ Deferred.prototype.fail = function(cb){ Deferred.prototype.resolve = function(){ // 模拟$.when的实现 function callback(){ for(var i=0; i< aLen; i++){ // 自定义异步执行的方法 // 调用测试 |
如上代码,原理即为:使用Deferred来保存回调函数和状态,等异步操作完成后,改变状态,触发相应回调函数。
使用Primose方式解决异步编程回调的一些问题
如果要使用Priomse方式来解决异步编程带来的回调嵌套问题,
那么我们势必需要将我们的所有包含异步操作的函数进行一层封装,
封装成Promise对象,我们才能使用类似:
$.when(promise1,promise2,....).then(...);
回到开头提到的动画的例子,我们可以这样子来实现:
代码如下 | 复制代码 |
function animate(dis,time){ $('.boll').on('click',function(){ |
when里参数必须是Promise对象,when(xxx) 返回的也是一个Promise。
所以这必然增加了我们一些代码量,但是为了更好的可读性和可维护性,是值得的。