posts - 3, comments - 1, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

给你的元素加一把锁--Prototype.js

Posted on 2006-09-14 18:26 govo 阅读(360) 评论(0)  编辑  收藏

   在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一下了。

 以上就是全文内容,请各位指点。

 


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问