在Ajax应用中,我们常常要频繁更改某一元素的值。例如有一ID为"pageBody"的元素,我们想把所有文章内容都在这里显示,做到局部刷新的Ajax应用。但如果因为网速较慢,使得此元素在接收信息时就被用户执行其它行为,而改变此元素的内容了,而之前的接收信息的线程还在进行着,当此线程完成了,又把pageBody的值改了一下,此时用户会觉得不知所措,怎么这块东西闪来闪去的?严重者,会因为子元素的消失而出现JS错误的现象。
为了解决此问题,有两个方法:第一、在执行线程(假设执行一次取值为一个线程)的时候,建立一个满屏的DIV,使得用户无法执行其它行为;第二、制作一把锁,把此元素锁起来,当其它线程想改变它的值时先查检此元素是否上锁。
第一种方法使得用户进入了等待状态,虽然页面没有刷新,但与没有使用Ajax的页面没什么分别,所以在非不得已的情况下都不要使用此方法。
下面我说说第二种方法--制作元素锁。
其实要实现这个锁,原理很简单,与java中的线程锁有点类似,可惜偶对java的线程锁理解不深入,所以在javaScript中此锁与java的线程锁应该又会有很大的不同,甚至完全不是一个回事。
首先,我们需要一个Object,
var
_key
=
{key:key,value:
true
};
其中key为此对象的标识,value是否为真就等于是否为锁定。
在java中,每一个Object对象都可以用作锁,但javaScript中不同,而且通过
1 while(true){
2 if(condition) break;
3 }
的方法根本行不通,因为这个while(true)会让浏览器僵死,Firefox会提示是否继续执行脚本,IE可能会说脚本有误,杀毒软件可能说这是病毒!
为了能统领全局,更灵活的掌控它,我们把锁都放到一个数组中:
1 var _mainlock=[];
同时,为了方便应用,我使用了Prototype.js,以扩展Array的方法,主要用这三个方法:
1、detect(iterator):集合中每个元素调用一次Iterator,返回第一个使Iterator返回True的元素,如果最终都没有为true的调用,那么返回null。
2、reject(iterator):返回所有等于false的元素。
3、each(iterator):把每个element做为第一个参数,element的index作为第一个参数调用iterator函数。
有了它们,我们可以创建一个Push来给 _mainlock加入唯一key的锁,类似HashMap原理:
var
_Push
=
function
(Obj)
{
var
unIns
=
_mainlock.reject(
function
(d)
{
return
d.key
==
Obj.key;}
);
_mainlock
=
unIns;
_mainlock.push(Obj);
}
只要执行_Push(_key)就可以把对象放入这个伪HashMap中去。如果已有相同的key的对象,则会覆盖它,没有就直接放入。
var
get
=
function
(key)
{
return
_mainlock.detect(
function
(d)
{
return
d.key
==
key;}
);
}
;
通过这个方法,就可以取得相应Key的锁了。
因为JavaScript对DOM的操作有着很多未知性,不可能总是通过我们预先定义的变量来满足要求,如一个列表,可能是有一行,也可能上千行,每一行的ID又是独立的,所以我们只能用另外的方法来预见之此行为,那就是通过应用HashMap的特性,以string为标识的唯一Key来统领所有将可能发生的事件。因此,再写一个方法:
var
Lock
=
function
(key)
{
var
_key
=
{key:key,value:
true
}
;
_Push(_key);
return
true
;
}
;
这样,只要有一个string类型的key,就可以建立一个锁对象了。以后,对锁的建立和获取,都可以通过上面三个方法来实现,只要一个string作为Key来操作锁,而无需知道锁的内部是如何构造。
接下来,我们要实现isWait(),sleep(),awake()和awakeAll()方法,以完善这个锁:
var
isWait
=
function
(key)
{
//
返回真表示锁,否则表示非锁
var
ins
=
GDnews.get(key);
if
(ins)
return
ins.value;
return
false
;
}
;
var
sleep
=
function
(key,time)
{
//
给锁上锁指定秒数,若干秒后自动解锁
GDnews.Lock(key);
window.setTimeout(
function
()
{GDnews.awake(key)}
,time);
}
;
var
awake
=
function
(key)
{
//
强行开锁
var
_key
=
{key:key,value:
false
}
;
GDnews._Push(_key);
return
false
;
}
;
var
awakeAll
=
function
()
{
//
强行打开所有锁
if
(
!
GDnews._mainlock)
return
"
all
"
;
var
newList
=
[];
GDnews._mainlock.each(
function
(d,index)
{
d.value
=
false
;
newList.push(d);
}
);
GDnews._mainlock
=
newList;
return
false
;
}
;
以后,当你使用Prototype.js的快捷键$()时,就可以看看目标是否为isWait,否的话就可以Lock或者sleep一下了。
以上就是全文内容,请各位指点。