这可能是个比较深的话题。何谓异步?
笼统地说,异步在javascript就是延时执行。严格来说,javascript中的异步编程能力都是由BOM与DOM提供的,如setTimeout,XMLHttpRequest,还有DOM的事件机制,还有HTML5新增加的webwork, postMessage,等等很多。这些东西都有一个共同的特点,就是拥有一个回调函数,实现控制反转。由于控制反转是更深奥的问题,这里不想展开。不过有点可以确认的,回调函数的存在打断了原来的执行流程,让它们自行在适当的时机出现并执行,这是个非常便捷的模式。对比主动式的轮询,你就知它多么节能。在同步编程,代码基本上自上向下执行,在异步编程,一些代码就要写到回调函数中,如果代码之间存在依赖,回调函数套回调函数的情况也不少见,这种套嵌结构对以后的维护来说简直是地狱。还有一种我们不得不面对的情况,try...catch无法捕捉几毫秒之后发生的异常。另外,除了setTimeout外,异步编程基本上由事件机制承担的,它们的回调函数什么时候发生基本上都是未知数,可能由于后台发生系统级错误,无法再发出响应,或者,系统忙碌,一时半刻响应不过来,这两种情况我们也必需提供一个策略,中断这操作,也就是所谓的abort,这些都是异步编程的所要处理的课题。
$.post( "/foo.json" ,
function (dataOfFoo) {
$.post( "/bar.json" ,
function (dataOfBar) {
$.post( "/baz.json" ,
function (dataOfBaz) {
alert([dataOfFoo, dataOfBar, dataOfBaz]);
});
});
});
|
function
throwError(){
throw
new Error( 'ERROR' );
}
try {
setTimeout(throwError, 3000);
} catch (e){
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这东西,我通常称之为异步列队,因为它们的确是需要两组由回调函接构成的队列,非常之形象。
在我们搬出异步列队之前,让我们看看普通的列队是怎么实现延迟的。
var
Queue = function (){
this .list = []
}
Queue.prototype = {
constructor:Queue,
queue: function (fn) {
this .list.push(fn)
return
this ;
},
dequeue: function (){
var
fn = this .list.shift()|| function (){};
fn.call( this )
}
}
|
这样调用它:
var
q = new Queue;
q.queue( function (){
log(1)
}).queue( function (){
log(2)
}).queue( function (){
log(3)
});
while (q.list.length){
q.dequeune();
}
|
但这是同步,想异步,我们需要用setTimeout,
var
el = document.getElementById(
"test"
);
var
q =
new
Queue();
q.queue(
function
(){
var
self =
this
;
el.innerHTML = 1
setTimeout(
function
(){
self.dequeue()
},1000);
}).queue(
function
(){
var
self =
this
;
el.innerHTML = 2
setTimeout(
function
(){
self.dequeue()
},1000);
}).queue(
function
(){
var
self =
this
;
el.innerHTML = 3
setTimeout(
function
(){
self.dequeue()
},1000);
}).dequeue()
如大家所见,这样写绝对不友好。我们需要把setTimeout整到Queue类中去,另对queue做一些修改,不要只弹出一个函数进行执行,通常情况下会对列队中的所有回调进行操作的,如domReay,多投事件。
var
Queue = function (){
this .list = []
}
Queue.prototype = {
constructor:Queue,
queue: function (fn) {
this .list.push(fn)
return
this ;
},
wait: function (ms){
this .list.push(ms)
return
this ;
},
dequeue: function (){
var
self = this , list = self.list;
var
el = list.shift()|| function (){};
if ( typeof
el == "number" ){
setTimeout( function (){
self.dequeue();
},el);
} else
if ( typeof
el == "function" ) {
el.call( this )
if (list.length)
self.dequeue();
}
}
}
|
Great,如果我们能自由控制每个回调的间隔,这对于做动画效果说,就变得非常简单了。但这Queue类相对我们最初定下的目标来说,还是差得远。Ajax,多投事件,domReay将统统划归于它的麾下,因此它需要用一些适用性更强的API。用过dojo的人也知,它的Deferred就像DNA的染色体一样,是双线的,可以捕捉不在同一时间线上的异常,而且这些列队不能像卫生筷那样用完一次就废了,这样就无法支撑多投事件的实现了。想要实现这些功能,就需要一个很复杂的东西,我将在第二部分隆重介绍我的异步列队,看它是如何优雅地解决这些问题。
分享到:
相关推荐
《JavaScript异步编程》这本书深入探讨了现代JavaScript开发中的关键主题——如何在不陷入混乱的情况下处理并发和并发任务。本书作者Trevor Burnham通过精确平衡的浏览器端和服务器端示例,为读者提供了一份简洁的...
JavaScript异步编程是前端开发领域中的一个重要概念,它允许程序在等待长时间操作(如网络请求)时继续执行其他任务,而不是简单地暂停或停止,从而提升用户体验。本书《JavaScript异步编程》作为图灵程序设计丛书的...
"JavaScript高性能编程"和"JavaScript异步编程"是两个关键的JavaScript专题,对于提升应用程序的性能和用户体验至关重要。 一、JavaScript高性能编程 1. **优化代码执行效率**:了解JavaScript引擎的工作原理,如...
JavaScript异步编程是Web开发中的核心技能,它使得开发者能够设计出快速响应的网络应用,提供流畅的用户体验。这本书的源码提供了深入理解和实践这些概念的机会。以下是对这个主题的详细探讨。 首先,我们要理解...
### JavaScript异步编程的四种方法 #### 概述 JavaScript是一种广泛使用的脚本语言,尤其在Web开发领域占据着核心地位。由于浏览器环境的限制,JavaScript最初被设计为单线程执行模型。这意味着在同一时间只能执行...
### JavaScript异步编程知识点概述 #### 一、异步编程概念 在JavaScript中,异步编程是一种处理长时间运行操作而不阻塞主线程的方法。这种方式允许程序在等待某些操作(如I/O操作、网络请求等)完成的同时,继续...
在早期的JavaScript异步编程中,回调函数是处理异步操作的主要方式。然而,嵌套回调函数(俗称回调地狱)会导致代码难以阅读和维护。例如: ```javascript makeAjaxCall('***', (result) => { result = JSON.parse...
JavaScript异步编程是前端开发中的重要概念,它允许在执行长时间运行的任务时不会阻塞主线程,从而提升用户体验。异步编程的核心在于,它不会立即得到结果,而是在某个未来的时刻,当任务执行完毕后,才会得到通知。...
JavaScript异步编程是Web开发中的核心概念,尤其在构建交互性强、响应迅速的网页应用时不可或缺。这篇博客“JavaScript异步编程学习”可能探讨了如何有效地处理非阻塞操作,以避免程序因等待I/O或其他耗时任务而陷入...
3. **JavaScript异步编程**: 异步编程是JavaScript的重要特性,用于处理耗时操作,如网络请求和文件读写,以避免阻塞主线程。主要方法有: - 回调函数:最基础的异步处理方式,但可能导致回调地狱问题。 - 事件...
藏经阁-JavaScript异步编程 JavaScript异步编程是JavaScript语言的一大特点,它可以使得JavaScript语言在单线程的情况下,执行多个任务,而不需要阻塞其他任务。异步编程的解决方案有多种,包括回调函数、Promise、...
本文将深入讲解JavaScript异步编程的基础和高级概念,帮助开发者理解并掌握这一核心技能。 1. **异步编程的基本概念** 在JavaScript中,异步编程意味着某些操作不会阻塞程序的执行,而是以非阻塞的方式进行。这是...
JavaScript 异步编程
本文主要介绍了JavaScript异步编程设计的相关内容,为了构建快速响应的网络应用,文章深入探讨了异步编程的多种方法,并提供了实用的实践案例。异步编程是Web开发中的一个重要概念,它允许程序在等待耗时操作(如I/O...
详解JavaScript异步编程中jQuery的promise对象的作用 Promise 对象是 JavaScript 异步编程中的一种重要概念,特别是在 jQuery 库中。Promise 对象的主要作用是解决异步编程中的回调地狱问题,提供了一种简洁的方式...
### JavaScript异步编程知识点 #### 一、异步编程基础概念 - **定义**:异步编程是指在程序运行过程中,某段代码不阻塞主线程执行其他任务的能力。这在处理耗时操作如网络请求、文件读写时尤为重要。 - **同步与...
### JavaScript异步编程的Promise模式 #### 引言 随着Web技术的发展,特别是Web 2.0技术的应用,用户对网站交互性和响应速度的要求越来越高。在这种背景下,异步编程成为了现代Web开发中不可或缺的一部分。然而,...