简单的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不间断滚动效果(模拟百度新闻支持文字/图片/垂直滚动)
Feb 05 Javascript
js字符串完全替换函数分享
Dec 03 Javascript
jQuery中document与window以及load与ready 区别详解
Dec 29 Javascript
Jquery的基本对象转换和文档加载用法实例
Feb 25 Javascript
JavaScript字符串常用类使用方法汇总
Apr 14 Javascript
jQuery实现的超链接提示效果示例【附demo源码下载】
Sep 09 Javascript
谈谈因Vue.js引发关于getter和setter的思考
Dec 02 Javascript
JS使用ActiveXObject实现用户提交表单时屏蔽敏感词功能
Jun 20 Javascript
纯JavaScript实现实时反馈系统时间
Oct 26 Javascript
vuex操作state对象的实例代码
Apr 25 Javascript
webpack项目使用eslint建立代码规范实现
May 16 Javascript
低门槛开发iOS、Android、小程序应用的前端框架详解
Oct 16 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脚本的10个技巧(6)
2006/10/09 PHP
php执行sql语句的写法
2009/03/10 PHP
谈谈新手如何学习PHP 默默经典版本
2009/08/04 PHP
PHP常用技巧总结(附函数代码)
2012/02/04 PHP
php生成N个不重复的随机数实例
2013/11/12 PHP
php下pdo的mysql事务处理用法实例
2014/12/27 PHP
什么是PHP文件?如何打开PHP文件?
2017/06/27 PHP
详解如何在云服务器上部署Laravel
2017/06/30 PHP
PHP 扩展Memcached命令用法实例总结
2020/06/04 PHP
关于extjs4如何获取grid修改后的数据的问题
2013/08/07 Javascript
javascript判断office版本示例
2014/04/11 Javascript
JavaScript中的逻辑判断符&amp;&amp;、||与!介绍
2014/12/31 Javascript
js全选实现和判断是否有复选框选中的方法
2015/02/17 Javascript
javascript 中的 delete及delete运算符
2015/11/15 Javascript
BOM系列第一篇之定时器setTimeout和setInterval
2016/08/17 Javascript
对javascript继承的理解
2016/10/11 Javascript
javascript设计模式之Adapter模式【适配器模式】实现方法示例
2017/01/13 Javascript
JS复制对应id的内容到粘贴板(Ctrl+C效果)
2017/01/23 Javascript
如何抽象一个Vue公共组件
2017/10/17 Javascript
weebox弹出窗口不居中显示的解决方法
2017/11/27 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
详解如何在vue-cli中使用vuex
2018/08/07 Javascript
手把手教你使用TypeScript开发Node.js应用
2019/05/06 Javascript
[46:43]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第三局
2016/02/28 DOTA
[00:12]2018DOTA2亚洲邀请赛 Somnus丶M出阵单挑
2018/04/06 DOTA
Python实现栈的方法
2015/05/26 Python
python出现&quot;IndentationError: unexpected indent&quot;错误解决办法
2017/10/15 Python
Python openpyxl 遍历所有sheet 查找特定字符串的方法
2018/12/10 Python
python 实现将txt文件多行合并为一行并将中间的空格去掉方法
2018/12/20 Python
python利用小波分析进行特征提取的实例
2019/01/09 Python
Python3 关于pycharm自动导入包快捷设置的方法
2019/01/16 Python
python获取点击的坐标画图形的方法
2019/07/09 Python
关于python中plt.hist参数的使用详解
2019/11/28 Python
python 解决flask uwsgi 获取不到全局变量的问题
2019/12/22 Python
tensorflow 模型权重导出实例
2020/01/24 Python
法国在线购买汽车轮胎网站:123pneus.fr
2019/02/25 全球购物