javascript 异步编程javascript

这可能是个比较深的话题。何谓异步?

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

$.post("/foo.json", function (dataoffoo) {//多层套嵌结构的ajax回调

$.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()

var el = document.getelementbyid("test");

var q = new queue();

q.queue(function(){

el.innerhtml = 1

})

.wait(1000)

.queue(function(){

el.innerhtml = 2

})

.wait(1000)

.queue(function(){

el.innerhtml = 3

})

.wait(1000)

.queue(function(){

el.innerhtml = 4

})

.wait(1000)

.queue(function(){

el.innerhtml = 5

})

.wait(1000)

.queue(function(){

el.innerhtml = 6

})

.wait(1000)

.queue(function(){

el.innerhtml = 7

})

.dequeue()

运行代码

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


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/

你可能感兴趣的:(javascript)