简单的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 相关文章推荐
javascript学习笔记(十九) 节点的操作实现代码
Jun 20 Javascript
jQuery控制iFrame(实例代码)
Nov 19 Javascript
JavaScript比较两个对象是否相等的方法
Feb 06 Javascript
JS实现刷新父页面不弹出提示框的方法
Jun 22 Javascript
JS判断日期格式是否合法的简单实例
Jul 11 Javascript
微信小程序 chooseImage选择图片或者拍照
Apr 07 Javascript
简单实现JS上传图片预览功能
Apr 14 Javascript
js简易版购物车功能
Jun 17 Javascript
基于JavaScript实现微信抢红包功能
Jul 20 Javascript
Vue.directive()的用法和实例详解
Mar 04 Javascript
vue2.0 + ele的循环表单及验证字段方法
Sep 18 Javascript
VsCode里的Vue模板的实现
Aug 12 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
phpfans留言版用到的数据操作类和分页类
2007/01/04 PHP
Win2003服务器安全加固设置--进一步提高服务器安全性
2007/05/23 PHP
PHP cookie,session的使用与用户自动登录功能实现方法分析
2019/06/05 PHP
JavaScript中this关键字使用方法详解
2007/03/08 Javascript
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
2007/04/12 Javascript
jquery使用jquery.zclip插件复制对象的实例教程
2013/12/04 Javascript
node.js中的http.request方法使用说明
2014/12/14 Javascript
文字垂直滚动之javascript代码
2015/07/29 Javascript
基于JavaScript实现通用tab选项卡(通用性强)
2016/01/07 Javascript
JS在Chrome浏览器中showModalDialog函数返回值为undefined的解决方法
2016/08/03 Javascript
巧用Javascript的逻辑运算符
2016/12/02 Javascript
Javascript中的 “&amp;” 和 “|” 详解
2017/02/02 Javascript
js鼠标跟随运动效果
2017/03/11 Javascript
详解React Native开源时间日期选择器组件(react-native-datetime)
2017/09/13 Javascript
vue input输入框关键字筛选检索列表数据展示
2020/10/26 Javascript
js String.prototype.trim字符去前后空格的扩展
2020/08/23 Javascript
微信小程序学习总结(一)项目创建与目录结构分析
2020/06/04 Javascript
vue3.0 项目搭建和使用流程
2021/03/04 Vue.js
python实现封装得到virustotal扫描结果
2014/10/05 Python
基于Python 的进程管理工具supervisor使用指南
2016/09/18 Python
python实现多张图片拼接成大图
2019/01/15 Python
python and or用法详解
2019/06/26 Python
对python中的float除法和整除法的实例详解
2019/07/20 Python
python连接、操作mongodb数据库的方法实例详解
2019/09/11 Python
详解Python 循环嵌套
2020/07/09 Python
Python实现迪杰斯特拉算法并生成最短路径的示例代码
2020/12/01 Python
canvas学习总结三之绘制路径-线段
2019/01/31 HTML / CSS
美国婴儿用品及配件购买网站:Munchkin
2019/04/03 全球购物
Bandier官网:奢侈、时尚前卫的健身服装首选目的地
2020/07/05 全球购物
医学毕业生自荐信
2013/10/11 职场文书
2014年党员学习“三严三实”思想汇报
2014/09/15 职场文书
婚礼答谢词
2015/01/04 职场文书
龙猫观后感
2015/06/09 职场文书
初中政治教师教学反思
2016/02/23 职场文书
jackson json序列化实现首字母大写,第二个字母需小写
2021/06/29 Java/Android
redis不能访问本机真实ip地址的解决方案
2021/07/07 Redis