简单的JavaScript互斥锁
简单的JavaScript互斥锁
去年有⼏个项⽬需要使⽤JavaScript互斥锁,所以写了⼏个类似的,这是其中⼀个:
View Code
⼀个互斥锁的⼏个元素是:
锁与解锁
等待队列
执⾏⽅法
以上锁的⽤法:
//定义锁的名称
var lock = 'scrollTop()';//使⽤锁
$.indream.async.lock(lock, function () {
var scrollTop = $(window).scrollTop();
var timer;
var fullTime = 100;
for (timer = 0; timer <= fullTime; timer += 10) {
setTimeout('$(window).scrollTop(' + (scrollTop * (fullTime - timer) / fullTime) + ');', timer);
}
//释放锁
setTimeout('$.leaseLock("' + lock + '");', fullTime);
});
关于这次所的实现,简单说明下。
-
⾃旋锁还是信号量
JavaScript本⾝没有锁的功能,所以做的锁都是在⾼层实现的。
依据JavaScript单线程的原理,JS的线程资源⼗分有限,⾮常不适合使⽤⾃旋锁,所以选择了使⽤信号量。
⾃旋锁实现起来的样⼦⼤致是这样的,当然do while更多⽤了:
while(true) {
//
}
这样必然需要占满线程资源,可惜JS只有⼀条线程可以⽤来执⾏,所以这样做⼗分不适⽤。当然,有需要可以选择setInterval和clearInterval的组合去实现,效果也会不错。
这⾥选⽤了信号量的⽅式,原理也简单,就如代码那么短。⼯作的执⾏顺序⼤致是:
把代码段(回调的action)推⼊等待队列
判断当前锁是否被持有,如果被持有则等待释放,否则获取该锁,执⾏回调
当锁被释放,则在等待队列中shift出下⼀个回调,将锁传递给它并执⾏
-⾃动释放还是⼿动释放
看起来最舒服的⽅式当然是锁住之后当当前程序执⾏完就⾃动释放,不过这样并不容易,因为有更多的情况需要⾃定义释放场景。
本⾝使⽤锁的就是在异步中的⽅法,所以各种通常也会出现其他异步内容,⽐如AJAX、jQuery 动画。这个时候,⾃动释放就不符合需求了,因为实际上真正的“执⾏完毕”是在它内部的异步回调完成后,也就是基本上只有开发⼈员⾃⼰能把握,所以这⾥选择了⼿释放。
不过还是有缺陷的,就是重复释放。
可以看到所有的锁的对象都是公有的,或者应该说JS所有对象都是公有的,除⾮使局部变量在访问级别上进⾏隔离。不过这⾥“锁”本⾝就是个公共资源,所以没办法处理。
这⾥可以做的优化应该是像setInterval和clearInterval的那样,以公共的锁名称进⾏加锁,以私有的锁ID进⾏解锁,就可以防⽌重复释放了。不过上⾯这段⽼代码中没有,估计很快就会⽤到的了。
绿⾊通道:好⽂要顶关注我收藏该⽂与我联系
Indream Luo
关注 - 1
粉丝 - 27
+加关注
1
(请您对⽂章做出评价)
上⼀篇:为jQuery添加Webkit的触摸⽅法⽀持
posted @ 2014-02-02 16:10 Indream Luo阅读(624) 评论(10) 编辑收藏
评论列表
#1楼 2014-02-02 16:59 BarretLee
如果没有使⽤worker,不会同时有两个程序操作资源,互斥的使⽤场景并不多。
你⽂中所说'JavaScript双线程的原理'是在哪⾥看到的?单线程吧?
⽀持(1)反对(0)
#2楼[楼主] 2014-02-02 17:52 Luo Indream
@BarretLee
引⽤
如果没有使⽤worker,不会同时有两个程序操作资源,互斥的使⽤场景并不多。
你⽂中所说'JavaScript双线程的原理'是在哪⾥看到的?单线程吧?
呵呵,“单线程”已修正,顺便到了后⾯俩错别字。多谢了。
我之前在两种场景常使⽤锁,⼀种是有⽐较多的Ajax请求,另⼀种是⽐较多的UI动画交互。⼀个是需要等到数据才能执⾏很多东西,⽽不同的Http请求速度不⼀致导致很多⿇烦,需要⽤锁;另⼀个是交互的时候需要等⼀些动画播放完毕才能执⾏其他的东西。如果两个场景同时出现,会使⽤⼤量的锁,⽐如我
做的IM。
⽀持(0)反对(0)
#3楼 2014-02-02 17:58 看门的判官
锁就是给数据加个开关来控制访问权
⽀持(0)反对(0)
#4楼[楼主] 2014-02-02 18:05 Luo Indream
@看门的判官
哈哈,对的,要⽂艺点说就是“让程序按照需要的顺序使⽤数据。”
我觉得是源⾃于⼀种权限模拟的需求。因为内存是共有的,但抽象后的业务对象不是,需要模拟出这种效果。
⽀持(0)反对(0)
#5楼 2014-02-02 21:44 BarretLee
⽐较多的 ajax 请求,你指的是两个 ajax 队列,⼀个读⼀个写?⽐较多的 UI 动画交互,你指的是,多次 js 操作然后需要⽴即渲染?这些问题根本没必要使⽤互斥锁来完成,单线程阻塞运⾏是 js 最⼤的⼀个特点,利⽤ js 的异步特性就可以处理上述的⼏个问题。
可以看看我上次写的JavaScript异步编程原理
需要使⽤互斥锁的场景,我也碰到过,⼀种是多 worker 读写数据,⼀种是多页⾯读写本地储存
或者 cookie,这些场景都是⼗分少见的。
⽀持(0)反对(0)
#6楼[楼主] 2014-02-02 22:55 Luo Indream
@BarretLee
引⽤
⽐较多的 ajax 请求,你指的是两个 ajax 队列,⼀个读⼀个写?⽐较多的 UI 动画交互,你
指的是,多次 js 操作然后需要⽴即渲染?这些问题根本没必要使⽤互斥锁来完成,单线程
阻塞运⾏是 js 最⼤的⼀个特点,利⽤ js 的异步特性就可以处理上述的⼏个问题。
可以看看我上次写的JavaScript异步编程原理
需要使⽤互斥锁的场景,我也碰到过,⼀种是多 worker 读写数据,⼀种是多页⾯读写本地
储存或者 cookie,这些场景都是⼗分少见的。
是的,我⽤的场景差不多。
⼀个实例是我做IM的时候,⽤⼤量的Ajax去读数据,但是⼜要减少服务器压⼒,所以会⽤到⽐较多的缓存。这时候理想的处理就是:判断是否有缓存->没有则去读->读到后缓存起来。不过实际情况是,⽐如打开⼀个会话,有⼀个⼈发了10条记录,那么就需要读取他的个⼈信息10次。为了防⽌并发读取浪费资源,那么负责读取的程序就应该互斥。
还有⼀个是在UI交互⽐较多的情况下会发⽣。在某个动画(向左切换)播放完之前触发了某个动画(向右切换),⽽原有动画并不是阻塞连续(组合动画)的,很容易出现先解决了后来者。这样出现的原因就是机制上不阻塞,但是我们需要它阻塞,所以就要⽤到锁了。
不过很多情况可以从设计到⽅案上进⾏替换解决,也可能会有更优的⽅案。⼀般需要锁的情况都是与浏
览器内核其他线程交互相关的情况,⽐如UI渲染、计时器、AJAX请求、资源加载之类的。要⼀般单执⾏JS⾃⾝任务的情况下,需要锁的并不多,原有的回调、订阅机制就很够⽤了。
P.S.
你的那⽚博客内容挺全,学习了。本⾝不是做前端的,所以要多多向前端⽜们学习下。
⽀持(0)反对(0)
#7楼 2014-02-03 10:10 mr.cui
什么情况下需要这个东西呢?
感觉好像是程序员的程序想法,也就是刚开始是为了解决⼀个问题要抽象到⼀个通⽤的⽅法,做着做着,⽬的结果逐渐偏离问题本质了,最后做出来的东西要么做复杂了要么不实⽤。javascript程序设计软件
⽀持(0)反对(0)
#8楼 2014-02-03 10:16 winpzs
没必要吧? javascript本来就只是单线程, AJAX、jQuery动画⽤jQuery的Deferred就完美解决了.⽀持(1)反
对(0)
#9楼 2014-02-03 11:10 麦舒
@winpzs
引⽤
没必要吧? javascript本来就只是单线程, AJAX、jQuery动画⽤jQuery的Deferred就完美解决了.
好象是这么回事

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。