JS(AS)中的原子操作
原子操作这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
当然JS是单线程的,所以不存在线程打断这么一说,我只是从Java中借引了这么一个概念。如果一段JS代码在执行过程中没有未知操作被引入,那么这段代码就是100%可控和安全的,这就是原子操作。反之非原子操作可能会因为外界操作的引入导致代码变得难以控制而产生隐晦的bug。
下面举例说明非原子操作可能会带来的问题
function start()
{
player = new Player();
player.start();
fireEvent('start');
player.resume();
fireEvent('play');
} function stop()
{
player.pause();
fireEvent('pause');
player.stop();
player = null;
fireEvent('stop');
}
这段代码中定义两个方法,start表示开始播放视频,里面分别有两段原子操作,在每个原子操作结束之后都向外发送了事件;stop方法类似。代码看起来简单而完美,但由于这两个方法都不是原子操作,所以可能会存在隐患。
下面我们用同样简单的方式使用这两个方法就会产生混乱的结果。
on('start', function(){
stop();
});
start();
这段代码试图让播放器一开始播放就停止,意图明确。但是它却会让实际执行结果变成下面这样
player = new Player();
player.start();
fireEvent('start');
//监听start事件后引入的操作
player.pause();
fireEvent('pause');
player.stop();
player = null;
fireEvent('stop');
//end
player.resume();
fireEvent('play');
这段代码对外界来说居然在stop事件发生之后还会发生一次play事件,堪称诡异。
究其原因是因为触发play事件后引入外部操作导致下一个原子操作所依赖的前提改变。这就是我说的非原子操作的隐患。
那么如何避免这种问题呢,把代码改成这样就行
function start()
{ if (!started)
{
player = new Player();
player.start();
started = true;
fireEvent('start');
} if (started && !played)
{
player.resume();
played = true;
fireEvent('play');
}
} function stop()
{ if (started && played)
{
player.pause();
played = false;
fireEvent('pause');
} if (started)
{
player.stop();
player = null;
started = false;
fireEvent('stop');
}
}
只需要给每个原子操作加上足够的前提判断就可以避免上述问题。
有时候我们无法避免非原子操作,但是我们要认清哪些是原子操作,不要想当然得认为上一个原子操作产生的结果必然会是下一个原子操作的环境。在每个原子操作前加上足够的判断。
JS(AS)中的原子操作的更多相关文章
- Firebug中调试中的js脚本中中文内容显示为乱码
Firebug中调试中的js脚本中中文内容显示为乱码 设置 页面 UFT-8 编码没用, 解决方法:点击 "Firebug"工具栏 中的"选项"---" ...
- js文件中函数前加分号和感叹号是什么意思?
本文转自:http://blog.csdn.net/h_o_w_e/article/details/51388500 !function(){}(); !有什么用? 从语法上来开,JavaScri ...
- Angularjs在控制器(controller.js)的js代码中使用过滤器($filter)格式化日期/时间实例
Angularjs内置的过滤器(filter)为我们的数据信息格式化提供了比较强大的功能,比如:格式化时间,日期.格式化数字精度.语言本地化.格式化货币等等.但这些过滤器一般都是在VIEW中使用的,比 ...
- 解决webkit浏览器中js方法中使用window.event提示未定义的问题
这实际上是一个浏览器兼容性问题,根源百度中一大堆,简要说就是ie中event对象是全局变量,所以哪里都能使用到,但是webkit内核的浏览器中却不存在这个全局变量event,而是以一个隐式的局部变量的 ...
- 在JS方法中返回多个值的三种方法
在使用JS编程中,有时需要在一个方法返回两个个或两个以上的数据,用下面的几种方法都可以实现: 1 使用数组的方式,如下: <html> <head> <title> ...
- 关于js代码中与或运算符||&&的妙用
看bootstrap时看到如下一行JavaScript代码产生了疑惑. return window.pageYOffset || e.scrollTop ||在这里的作用是什么呢? 首先明确概念,在j ...
- Handlebars.js循环中索引(@index)使用技巧(访问父级索引)
使用Handlebars.js过程中,难免会使用循环,比如构造数据表格.而使用循环,又经常会用到索引,也就是获取当前循环到第几次了,一般会以这个为序号显示在页面上. Handlebars.js中获取循 ...
- JS 正则表达式中的特殊字符
正则表达式中的特殊字符 字符 含意 \ 做为转意,即通常在"\"后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/\b/,转意为匹配一个 ...
- js jquery中 的数据类型
任何一门语言, buguan 是动态的, 还是像C语言的, 都有严格的 类型 "概念的", 这个是由于 编译器和解释器要求的, 需要的. 所以在是使用像 js, jquey ,ph ...
- 在Ext JS 6中添加本地化包
我在官方论坛发的帖子终于有人恢复了,也终于知道如何添加本地化包了.在Ext JS 6中,Ext JS属于经典工具包,而本地化是包含在经典工具包中,因而在app.json中,要添加本地化包,必须在cla ...
随机推荐
- 【Redis】使用Redis Sentinel实现Redis HA
阅读目录 1 sentinel down-after-milliseconds mymaster 30000 sentinel failover-timeout mymaster 18000 sent ...
- golang的连接池例子
github.com/jolestar/go-commons-pool 测试代码 package main import ( "github.com/jolestar/go-commons- ...
- 解决AD域认证问题—“未知的身份验证机制”
场景: Ad认证登录系统,之前正常.不知服务器调了什么,导致无法登录.提示信息如标题. 解决方案: DirectoryEntry adRoot = new DirectoryEntry("L ...
- Android Please ensure that adb is correctly located at问题解决
转载于:http://breezylee.iteye.com/blog/2032588 遇到问题描述: 运行android程序控制台输出 [2012-07-18 16:18:26 - ] The co ...
- sql语句延时执行或者是指定时间执行
--使用waitfor语句延迟或暂停程序的执行 --waitfor{delay'time'|time 'time'} delay是指间隔时间 最长到24小时 time是指定时间执行 waitfor d ...
- butterknife 使用注意事项
写了个demo,一直报错 Caused by: java.lang.IllegalStateException: Required view 'tv1' with ID 2131492943 for ...
- FindBugs插件
在日常开发过程中难免会因为一时疏忽而留下一些Bug,这些Bug就是埋在程序里的定时炸弹,如果不能及时铲除就会导致程序的不稳定,异常或闪退的现象,从而导致用户的体验的下降.那么怎么才能找出这些埋在程序里 ...
- Java的安全性和可移植性
Java的这两个特性,关键在于Java编译器的输出并不是可执行的代码,而是字节码 bytecode. 字节码是一套设计用来在Java运行时系统下执行的高度优化的指令集,该Java运行 ...
- c# 对话框交换数据
本例是一个管理联系人信息的小程序,程序有两个窗体,一个主窗体,在listview控件中显示联系人信息列表,一个对话框窗体,用来显示和修改 某个联系人的信息.通过主窗体的菜单命令,可以打开对话框,并把主 ...
- AP_AP系列 - 发票管理分析(案例)
2014-07-07 Created By BaoXinjian