简单的JavaScript互斥锁分享


Posted in Javascript onFebruary 02, 2014

去年有几个项目需要使用JavaScript互斥锁,所以写了几个类似的,这是其中一个:

//Published by Indream Luo
//Contact: indreamluo@qq.com
//Version: Chinese 1.0.0
!function ($) {
    window.indream = window.indream || {};
    $.indream = indream;
    indream.async = {
        //
        //锁
        //lock: 锁的编号
        //action: 解锁后执行的方法
        //
        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);

一个互斥锁的几个元素是:

•锁与解锁
•等待队列
•执行方法
以上锁的用法:

//定义锁的名称
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进行解锁,就可以防止重复释放了。不过上面这段老代码中没有,估计很快就会用到的了。

Javascript 相关文章推荐
jquery $.ajax入门应用一
Nov 19 Javascript
jquery 模拟类搜索框自动完成搜索提示功能(改进)
May 24 Javascript
CSS和Javascript简单复习资料
Jun 29 Javascript
JavaScript全局函数使用简单说明
Mar 11 Javascript
Extjs中通过Tree加载右侧TabPanel具体实现
May 05 Javascript
js控制页面的全屏展示和退出全屏显示的方法
Mar 10 Javascript
详解JavaScript中数组的reduce方法
Dec 02 Javascript
Javascript中click与blur事件的顺序详析
Apr 25 Javascript
element-ui组件table实现自定义筛选功能的示例代码
Mar 15 Javascript
详解Vue中CSS样式穿透问题
Sep 12 Javascript
js实现飞机大战游戏
Aug 26 Javascript
JS数组转字符串实现方法解析
Sep 04 Javascript
在百度知道团队中快速审批新成员的js脚本
Feb 02 #Javascript
基于jquery的simpleValidate简易验证插件
Jan 31 #Javascript
基于JQuery实现的图片自动进行缩放和裁剪处理
Jan 31 #Javascript
jquery为页面增加快捷键示例
Jan 31 #Javascript
通过pjax实现无刷新翻页(兼容新版jquery)
Jan 31 #Javascript
jquery 页面滚动到底部自动加载插件集合
Jan 31 #Javascript
基于JQuery实现滚动到页面底端时自动加载更多信息
Jan 31 #Javascript
You might like
php 文件上传系统手记
2009/10/26 PHP
php生成唯一的订单函数分享
2015/02/02 PHP
部署PHP时的4个配置修改说明
2015/10/19 PHP
Redis使用Eval多个键值自增的操作实例
2016/11/04 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
jQuery下通过replace字符串替换实现大小图片切换
2012/05/22 Javascript
JQuery实现鼠标移动到图片上显示边框效果
2014/01/09 Javascript
javascript判断chrome浏览器的方法
2014/03/26 Javascript
js关于命名空间的函数实例
2015/02/05 Javascript
使用JavaScript实现ajax的实例代码
2016/05/11 Javascript
Bootstrap源码解读标签、徽章、缩略图和警示框(8)
2016/12/26 Javascript
JS实现选定指定HTML元素对象中指定文本内容功能示例
2017/02/13 Javascript
如何将 jQuery 从你的 Bootstrap 项目中移除(取而代之使用Vue.js)
2017/07/17 jQuery
angular使用bootstrap方法手动启动的实例代码
2017/07/18 Javascript
使用Node.js实现RESTful API的示例
2017/08/01 Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
2018/01/08 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
2019/08/27 jQuery
原生JavaScript创建不可变对象的方法简单示例
2020/05/07 Javascript
Python 时间操作例子和时间格式化参数小结
2014/04/24 Python
python实现zabbix发送短信脚本
2018/09/17 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
pycharm修改文件的默认打开方式的步骤
2019/07/29 Python
解决TensorFlow调用Keras库函数存在的问题
2020/07/06 Python
python中通过pip安装库文件时出现“EnvironmentError: [WinError 5] 拒绝访问”的问题及解决方案
2020/08/11 Python
Python collections.deque双边队列原理详解
2020/10/05 Python
可持续木材、生态和铝制太阳镜:Proof Eyewear
2019/07/24 全球购物
如何让Java程序执行效率更高
2014/06/25 面试题
编写一个类体现构造,公有,私有方法,静态,私有变量
2013/08/10 面试题
《狼》教学反思
2014/03/02 职场文书
个人评语大全
2014/05/04 职场文书
2014年百日安全生产活动总结
2014/05/04 职场文书
2014年学校办公室工作总结
2014/12/19 职场文书
运动会闭幕词
2015/01/28 职场文书
求职简历自我评价怎么写
2015/03/10 职场文书
公司仓库管理制度
2015/08/04 职场文书
CSS 制作波浪效果的思路
2021/05/18 HTML / CSS