lock:
function
(lock, action) {
$.indream.async.waitings[lock]
= $.indream.async.waitings[lock] ||
[];
$.indream.async.waitings[lock].push(action);
//
如果该锁未被使用,则当前action阻塞该锁
if
(!$.indream.async.lockStatus[lock] &&
action) {
$.indream.async.lockStatus[lock]
=
true
;
if
(arguments.length > 2
) {
var
args = 'arguments[2]'
;
for
(
var
i = 3; i < arguments.length; i++
) {
args
+= ', arguments[' + i + ']'
;
eval(
'$.indream.async.action.call(action, ' + args + ')'
);
}
else
{
$.indream.async.action.call(action);
//
解锁
//
lock: 锁的编号
releaseLock:
function
(lock) {
$.indream.async.waitings[lock].shift();
//
如果等待队列有对象,则执行等待队列,否则解锁
if
($.indream.async.waitings[lock].length) {
$.indream.async.waitings[lock][
0
]();
}
else
{
$.indream.async.lockStatus[lock]
=
false
;
//
锁的状态
lockStatus: [],
//
等待事件完成
//
lock:锁编码,相同的编码将被整合成一个序列,触发时同时触发
wait:
function
(lock, action) {
$.indream.async.waitings[code]
= $.indream.async.waitings[code] ||
[];
$.indream.async.waitings[code].push(action);
//
等待序列
waitings: [],
//
数据缓存
action: {
//
监听和回调的相关方法
callback: {
//
监听
listen:
function
(actionName, callback) {
var
list =
$.indream.async.action.callback.list;
list[actionName]
= list[actionName] ||
[];
list[actionName].push(callback);
//
回调
call:
function
(actionName, args) {
var
list =
$.indream.async.action.callback.list;
if
(list[actionName] &&
list[actionName].length) {
for
(
var
i
in
list[actionName]) {
$.indream.async.action.call(list[actionName][i], args);
//
现有的回调列表
list: []
//
根据方法是否存在和参数是否存在选择适当的执行方式
call:
function
(action) {
if
(action) {
if
(arguments.length > 1
) {
var
args = 'arguments[1]'
;
for
(
var
i = 2; i < arguments.length; i++
) {
args
+= ', arguments[' + i + ']'
;
eval(
'action(' + args + ')'
);
}
else
{
action();
}(window.jQuery);
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('$.indream.async.releaseLock("' + lock + '");', fullTime);
关于这次所的实现,简单说明下。
-自旋锁还是信号量
JavaScript本身没有锁的功能,所以做的锁都是在高层实现的。
依据JavaScript单线程的原理,JS的线程资源十分有限,非常不适合使用自旋锁,所以选择了使用信号量。
自旋锁实现起来的样子大致是这样的,当然do while更多用了:
while(true) {
//do something...
这样必然需要占满线程资源,可惜JS只有一条线程可以用来执行,所以这样做十分不适用。当然,有需要可以选择setInterval和clearInterval的组合去实现,效果也会不错。
这里选用了信号量的方式,原理也简单,就如代码那么短。工作的执行顺序大致是:
把代码段(回调的action)推入等待队列
判断当前锁是否被持有,如果被持有则等待释放,否则获取该锁,执行回调
当锁被释放,则在等待队列中shift出下一个回调,将锁传递给它并执行
-自动释放还是手动释放
看起来最舒服的方式当然是锁住之后当当前程序执行完就自动释放,不过这样并不容易,因为有更多的情况需要自定义释放场景。
本身使用锁的就是在异步中的方法,所以各种通常也会出现其他异步内容,比如AJAX、jQuery动画。这个时候,自动释放就不符合需求了,因为实际上真正的“执行完毕”是在它内部的异步回调完成后,也就是基本上只有开发人员自己能把握,所以这里选择了手释放。
不过还是有缺陷的,就是重复释放。
可以看到所有的锁的对象都是公有的,或者应该说JS所有对象都是公有的,除非使局部变量在访问级别上进行隔离。不过这里“锁”本身就是个公共资源,所以没办法处理。
这里可以做的优化应该是像setInterval和clearInterval的那样,以公共的锁名称进行加锁,以私有的锁ID进行解锁,就可以防止重复释放了。不过上面这段老代码中没有,估计很快就会用到的了。