文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Javascript 异步编程

2024-12-03 19:19

关注

[[346478]]

笼统地说,异步在javascript就是延时执行。严格来说,javascript中的异步编程能力都是由BOM与DOM提供的,如setTimeout,XMLHttpRequest,还有DOM的事件机制,还有HTML5新增加的webwork, postMessage,等等很多。这些东西都有一个共同的特点,就是拥有一个回调函数,实现控制反转。由于控制反转是更深奥的问题,这里不想展开。不过有点可以确认的,回调函数的存在打断了原来的执行流程,让它们自行在适当的时机出现并执行,这是个非常便捷的模式。对比主动式的轮询,你就知它多么节能。在同步编程,代码基本上自上向下执行,在异步编程,一些代码就要写到回调函数中,如果代码之间存在依赖,回调函数套回调函数的情况也不少见,这种套嵌结构对以后的维护来说简直是地狱。还有一种我们不得不面对的情况,try...catch无法捕捉几毫秒之后发生的异常。另外,除了setTimeout外,异步编程基本上由事件机制承担的,它们的回调函数什么时候发生基本上都是未知数,可能由于后台发生系统级错误,无法再发出响应,或者,系统忙碌,一时半刻响应不过来,这两种情况我们也必需提供一个策略,中断这操作,也就是所谓的abort,这些都是异步编程的所要处理的课题。

  1. $.post("/foo.json"function (dataOfFoo) {//多层套嵌结构的Ajax回调 
  2.   $.post("/bar.json"function (dataOfBar) { 
  3.     $.post("/baz.json"function (dataOfBaz) { 
  4.       alert([dataOfFoo, dataOfBar, dataOfBaz]); 
  5.     }); 
  6.   }); 
  7. }); 
  8.  
  9. function throwError(){ 
  10.   throw new Error('ERROR'); 
  11.  
  12. try{ 
  13.   setTimeout(throwError, 3000); 
  14. } catch(e){ 
  15.   alert(e);//这里的异常无法捕获 

由于在javascript编程,随时都碰到这样的需求,因此实现相关轻捷的API是重中之重。正如上面所说,它只少要有以下功能,能储存一组回调函数(domReary,多投事件,特效),在特定时刻中执行所有回调函数,如果发生错误能触发相应的处理函数(负向回调),能中止整个操作,从中断处再起操作,如果要求更多,我们还想能从串行转向并行,由并行转入串行。可能有许多概念大家听不懂,是不是?但想弄个好的特效,这些都是必需的。如果玩过后端JS的人,一定听说过node.js,现在基本成为它的代名词了。路由派发,IO操作,都是异步的,事件驱动的,为了实现优雅的异步编程,大牛们忙得焦头烂额,一个个方案被提出来,如do.js. step.js, async.js, flow.js……,不是太鸡肋,就是无法应用于前端。因此我们需要一个适合于前端的方案。

有件事我们必需明白,你想到的,人家都早已研究过了,并且已给出解决方案。十大javascript框架之一,Mochikit,就从Python的Twisted库搞来Deferred,后来又给dojo学去,现在你们又看到,相同的东西又出现在jQuery1.5上了。不过,Mochikit的Deferred还有一个不为人知的分支,由日本大牛cho45搞出来(他同时也搞什么BigInt,跨浏览器Testing,名气紧随amachang、uupaa、edvakf、nanto之后),叫JSDeferred。先说dojo那派系的(包括jQuery)的Deferred,一直处于无敌状态,与Common.js搞出一套规范,什么promises,then,when都是那时制定,jQuer基本全盘接受。另一分支,cho45的JSDeferred,构思非常奇特,没有使用数组来装载回调函数,而是通过setTimeout,image.onload, postMessage等异步机制巧妙地把维护列队地工作道回浏览器自身,虽然有致命缺陷,但其易用性也被日本JS界所首肯,我的Deferred对象就从它的基本上发展过来的。Deferred这东西,我通常称之为异步列队,因为它们的确是需要两组由回调函接构成的队列,非常之形象。

在我们搬出异步列队之前,让我们看看普通的列队是怎么实现延迟的。

  1. var Queue = function(){ 
  2.         this.list = [] 
  3.       } 
  4.       Queue.prototype = { 
  5.         constructor:Queue, 
  6.         queue:function(fn) { 
  7.           this.list.push(fn) 
  8.           return this; 
  9.         }, 
  10.         dequeue:function(){ 
  11.          var fn = this.list.shift()||function(){}; 
  12.          fn.call(this) 
  13.         } 

这样调用它:

  1. var q = new Queue; 
  2.       q.queue(function(){ 
  3.         log(1) 
  4.       }).queue(function(){ 
  5.         log(2) 
  6.       }).queue(function(){ 
  7.         log(3) 
  8.       }); 
  9.       while(q.list.length){ 
  10.         q.dequeune(); 

但这是同步,想异步,我们需要用setTimeout:

  1. var el = document.getElementById("test"); 
  2. var q = new Queue(); 
  3. q.queue(function(){ 
  4.   var self = this; 
  5.   el.innerHTML = 1 
  6.   setTimeout(function(){ 
  7.     self.dequeue() 
  8.   },1000); 
  9. }).queue(function(){ 
  10.   var self = this; 
  11.   el.innerHTML = 2 
  12.   setTimeout(function(){ 
  13.     self.dequeue() 
  14.   },1000); 
  15. }).queue(function(){ 
  16.   var self = this; 
  17.   el.innerHTML = 3 
  18.   setTimeout(function(){ 
  19.     self.dequeue() 
  20.   },1000); 
  21. }).dequeue() 

如大家所见,这样写绝对不友好。我们需要把setTimeout整到Queue类中去,另对queue做一些修改,不要只弹出一个函数进行执行,通常情况下会对列队中的所有回调进行操作的,如domReay,多投事件。

  1. var Queue = function(){ 
  2.   this.list = [] 
  3. Queue.prototype = { 
  4.   constructor:Queue, 
  5.   queue:function(fn) { 
  6.     this.list.push(fn) 
  7.     return this; 
  8.   }, 
  9.   wait:function(ms){ 
  10.     this.list.push(ms) 
  11.     return this; 
  12.   }, 
  13.   dequeue:function(){ 
  14.     var self = this, list = self.list; 
  15.     var el = list.shift()||function(){}; 
  16.     if(typeof el == "number"){ 
  17.       setTimeout(function(){ 
  18.         self.dequeue(); 
  19.       },el); 
  20.     }else if(typeof el == "function") { 
  21.       el.call(this) 
  22.       if(list.length) 
  23.         self.dequeue(); 
  24.     } 
  25.   } 

Great,如果我们能自由控制每个回调的间隔,这对于做动画效果说,就变得非常简单了。但这Queue类相对我们最初定下的目标来说,还是差得远。Ajax,多投事件,domReay将统统划归于它的麾下,因此它需要用一些适用性更强的API。用过dojo的人也知,它的Deferred就像DNA的染色体一样,是双线的,可以捕捉不在同一时间线上的异常,而且这些列队不能像卫生筷那样用完一次就废了,这样就无法支撑多投事件的实现了。想要实现这些功能,就需要一个很复杂的东西,我将在第二部分隆重介绍我的异步列队,看它是如何优雅地解决这些问题。

 

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯