异步编程的处理
JavaScript的执行流程是分为"同步"与"异步"
传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作。这也是造成异步编程困难的主要原因:
我们一直习惯于“线性”地编写代码逻辑,但是大量异步操作所带来的回调函数,会把我们的算法分解地支离破碎。
嵌套式回调
动画为例,下一个动画要等上一个执行完毕才可以继续,流程就会写到回调里面
//执行多个动画 $('ele1').animate({ opacity: '.5' }, 4000, function() { $('ele2').animate({ width: '100px' }, 2000, function() { $('ele3').animate({ height: '0' }, 2000); }); });
上面的代码编程逻辑也是正确的,但是针对这样的异步嵌套的回调逻辑,当我们的嵌套越多,代码结构层级会变得越来越深。首先是阅读上会变得困难,其次是强耦合,接口变得不好扩展。我们需要一种模式来解决这种问题,这就是Promises所要做的事情。
为了让前端们从回调的地狱中回到天堂, jQuery 也引入了 Promise 的概念。 Promise 是一种令代码异步行为更加优雅的抽象,有了它,我们就可以像写同步代码一样去写异步代码。这个东西看起来很复杂,实际上我们只要抓住核心的使用就可以了。
观察下边代码:
通过$.Deferred处理过的代码,很明显没有了回调的嵌套,虽然代码量看起来多了点,但是实际上,每一个代码执行部分都被封装了起来,只留了Deferred的接口处理了,等于是我们把执行的流程控制交给了Deferred,这样的好处就是我们在写嵌套函数的时候,可以用deferred提供的管道风格编写同步代码了
dtd.then(function() { //操作1 }).then(function() { //操作2 }).then(function() { //操作3 })
这里要了解3个步骤
var dtd = $.Deferred(); //创建 dtd.resolve(); //成功 dtd.then() //执行回调
具体的我们可以参考下jQuery的Deferred部分的API说明,点击此处
举例
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 6 <title>异步编程处理</title> 7 <style type="text/css"> 8 div { 9 background-color: yellow; 10 width: 200px; 11 height: 200px; 12 text-align: center; 13 border: 2px solid red; 14 margin: 3px; 15 font-size: 14px; 16 } 17 #block3,#block4{ 18 background-color: #CAE1FF; 19 } 20 button { 21 font-size: 14px; 22 } 23 </style> 24 <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script> 25 </head> 26 27 <body> 28 <button>点击测试回调处理</button> 29 <button>点击测试$.Deferred处理</button> 30 </br> 31 </br> 32 <div id="block1">block1执行动画</div> 33 <div id="block2">block2执行动画</div> 34 <div id="block3">block3执行动画</div> 35 <div id="block4">block4执行动画</div> 36 37 <script type="text/javascript"> 38 // 回调处理 39 $('button:first').click(function() { 40 $("#block1").animate({ 41 width: "50%" 42 }, 2000, function() { // 嵌套回调 43 $("#block2").animate({ 44 width: "50%" 45 }, 2000); 46 }); 47 }); 48 49 // jQuery的Deferred处理 50 $('button:last').click(function() { 51 52 function animate1() { 53 var dtd = $.Deferred(); // 生成Deferred对象 54 $("#block3").animate({ 55 width: "50%" 56 }, 2000, function() { 57 dtd.resolve(); // 改变Deferred对象的执行状态 58 }); 59 return dtd; 60 } 61 62 function animate2() { 63 var dtd = $.Deferred(); // 生成Deferred对象 64 $("#block4").animate({ 65 width: "50%" 66 }, 2000, function() { 67 dtd.resolve(); // 改变Deferred对象的执行状态 68 }); 69 return dtd; 70 } 71 72 var anim = animate1(); 73 74 anim.then(function() { 75 $("#block3").text('block3动画动画直接结束'); 76 return animate2(); 77 }).then(function() { 78 $("#block4").text('block4动画动画直接结束'); 79 }); 80 81 }); 82 83 84 </script> 85 </body> 86 87 </html>