`
yiminghe
  • 浏览: 1465429 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

开关状态信息的保存

阅读更多

系统中常常会存在大量的状态信息,特别是0-1值信息,某个条件是否达成,某个功能是否存在,某个操作是否成功等等,通常的做法是将各种状态条件编号,利用boolean数组来表示。

 

//0表示a功能,1表示b功能
//a功能生效
status[0]=true;
//b功能生效
status[1]=false;

 

由于大多数语言实际上是将boolean类型等同于整数类型,javascript也不例外,而其他语言和javascript不同的是:javascript目前必须运行在浏览器中,在特定条件下对于存储要求更加严格(例如cookie的4k限制),这时就要使用不常用的位操作来挖掘每一位存储的潜力。


将开关状态使用 0-1 二进制位表示,即将多个状态压缩到一个整数里面存储,一般一个整数有32位(javascript存在差异,尚不确定),则理论上节省了8倍的空间,代价则是增加了存取的运算。

 

1.存储数组


使用整数数组来拼成位集合

 

var store = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

 

2.设置状态


根据开关状态序号,定位到整数数组中的某个整数,设置特定的某个位为1

 

var index = Math.floor(num / 32),
                index2 = num % 32,
                mask = Math.pow(2, index2);
        store[index] |= mask;

 

3.清除状态


根据开关状态序号,定位到整数数组中的某个整数,设置特定的某个位为0

 

var index = Math.floor(num / 32),
all_one = (Math.pow(2, 32) - 1),
                index2 = num % 32,
                mask = all_one ^ Math.pow(2, index2);
        store[index] &= mask;

 

4.存储

 

最后存储到cookie时都要转换成字符串的格式,这里我们有三个选项

1.将 store 的每个 int,直接 toString() 转换成 10 进制字符串

2.将 store 的每个 int,toString(16) 转换成 16 进制字符串


但是这两种都没有充分利用一个字符字节的完全存储空间,即使16进制下4位就已经占据了一个字符字节的空间。


3.更优的解即是:对每8位,通过 String.fromCharCode 转为一个字节,最终存储到cookie。

 

5.解码

 

根据cookie中的字节,通过string.charCodeAt 即可获得该字节代表的数字,进一步通过位运算即可获取各个开关状态

 

var v = S.Cookie.get("test");
for (var i = 0; i < v.length; i++) {
  //解码
  var n = v[i].charCodeAt(0);
}

 

简单的可以通过对状态组数字的每一位进行检测是否0,1来得知状态设置为开的序号 :复杂度为 O(n) ,一般 n=32

 

//slower    
    function getOnesSlow(n,base,re) {    	
    	base=base||0;
    	var mask=1;
    	for(var i=0;i<32;i++){
    		if(n&mask) re.push(i);
    		mask=mask<<1;	
    	}
    }
 

其实存在更精巧的算法,主要是利用了负数的二进制其实就是由绝对值二进制取反后加一形成的,当一个数字和其负数进行按位与时,返回结果就是除了原数的最低位1保留外,其他都是0,例如

 

1010 对应负数为 111...0101,加1为 1111...0110

 

1111...0110 & 1010 = 10

 

结果 1 的位顺序数即为原数字 1010 的最低位 1的位顺序数

 

为了能根据 10..0 快速得知1所在的位顺序数,可以预先建立索引而不用循环计数:

 

    var bton={};
    var base=1;
    for(var i=0;i<32;i++){
    	bton[base]=i;
    	base=base<<1;
    }
 

那么现在就可以快速得到数字包含的1所在的位数数组:

 

//fastest one :
    function getOnes(n,base,re){
    	base=base||0;
    	while(n){
    		var mask=n&-n;
    		re.push(bton[mask]+base);
    		n &= ~mask;
    	}
    }
 

最快0次循环,即 n=0,最慢32次循环,即 n=1111...1(javascript位操作对象为32位整数),平均为 16 次循环,速度相比简单的逐位检测算法提高了一倍。

 

6.问题


在 cookie 中,每个字节并不能完整的表示8bit的信息量,因为ASCII中存在一些区间是特殊作用的字符(比如头32个)。作为HTTP头的一部分,理论上是不能使用这些字符的。
参考Uuencode算法(http://en.wikipedia.org/wiki/Uuencoding ),一般每个ANSI字符可以编码6bit的信息量。(感谢提醒)

 

demo

 

 

延伸阅读

 

 

javascript 在位操作领域也开始显露头角,国外有参照java流读取设计的 base64 解码器,甚至 deflate 解码器 ,从而产生了直接使用div构建png 图片的演示,非常不错,还有:

 

 Embedding Base64 Image Data into a Webpage


 Use Javascript to Take a Screenshot of a Flash Movie


 Base64 Encoded Images for Internet Explorer


 Parsing Base64 Encoded Binary PNG Images in JavaScript

 

 

 

分享到:
评论
2 楼 cloudgamer 2010-09-02  
好精细
1 楼 luolonghao 2010-08-30  
保存在cookie里这个确实是最理想的选择,有些程序员后端数据库也喜欢这么保存,呵呵

相关推荐

    AndroidListViewOFF带开关状态

    6. **状态保存与恢复**:如果应用需要在旋转屏幕或其他事件后保持开关状态,需要考虑数据的持久化,如使用SharedPreferences存储用户的选择状态。当应用重新启动时,可以从存储中恢复这些状态,并设置到对应的开关...

    SwitchButton 开关按钮的多种实现方式源码

    在Android开发中,`SwitchButton`(也称为开关按钮或切换按钮)是一种常见的UI元素,用于用户在两种状态之间进行切换。它通常表现为一个滑动开关,用户可以通过滑动来改变其状态,如开启或关闭某项功能。本文将详细...

    switch 开关 listview开关

    - `CheckedChangeListener`:为`Switch`添加`CheckedChangeListener`,可以监听开关状态的变化,当状态改变时,会触发`onCheckedChanged()`回调。 3. **在ListView中的应用**: - 自定义Adapter:创建自定义的`...

    Android ToggleButton的状态退出后可保存

    ToggleButton状态的保存,即使程序退出了,下次启动的时候依旧是ToggButton上次选定的状态。本程序适合有一定的编程基础的爱好者学习,用到了SharedPreferences模块,实现数据的保存和读取

    countandsave.rar_开关次数_时间 保存

    在这个项目中,单片机作为核心控制器,负责处理开关状态的检测、计数和时间记录。 2. **开关次数计算**: 通过连接单片机的输入引脚,可以实时监测开关的状态变化。每当开关动作时,单片机会检测到状态翻转,从而...

    开关按钮源代码

    - **React/Vue/Angular**(如果项目使用了这些框架):在组件中定义状态和生命周期方法,用于管理开关状态。 学习这个源代码,你可以深入理解如何将用户界面元素与后端逻辑连接起来,同时掌握如何处理用户输入和...

    在ListView中嵌套Switch开关,点击ListView条目来切换Switch的状态

    - 在代码中,可以通过`switch.setChecked(boolean)`来改变Switch的状态,`switch.setOnCheckedChangeListener()`来监听开关状态的变化。 5. **点击事件处理**: - 要实现在ListView中点击条目时切换Switch,我们...

    PHP 开关效果demo

    4. 数据库操作,如SQL语句的编写,用于保存和检索开关状态。 这样的互动功能在许多现代Web应用中非常常见,它可以应用于各种场景,如用户设置、功能启用/禁用等。通过理解并掌握这些技术,开发者可以创建更加动态和...

    8086 8个开关控制8个LED

    这需要在汇编代码中编写循环检查开关状态的逻辑,并根据这些状态更新LED的输出。 8086汇编语言程序通常由几部分组成:数据定义段(DATA SEGMENT)、代码段(CODE SEGMENT)、堆栈段(STACK SEGMENT)和初始化段...

    高仿墨迹开关设置

    墨迹开关,也被称为滑动开关或toggle switch,是一种在Android设备上常见用于切换两种状态的控件,例如打开或关闭某个功能。 首先,我们要了解Android中的开关控件基本类型:`Switch`和`CheckBox`。`Switch`是...

    android制作仿iphone开关控件

    4. **状态保存与恢复**: - 如果应用支持横竖屏切换或后台恢复,需要实现`Parcelable`接口,保存和恢复开关的状态。 5. **自定义属性**: - 在`res/values/attrs.xml`中定义自定义属性,如开关的宽度、高度、颜色...

    android 自定义开关 两段开关 三段开关

    继承自`View`或`CompoundButton`类,这取决于开关是否需要保存状态。如果需要,`CompoundButton`是一个更好的选择,因为它已经实现了`CheckedChangeListener`接口,可以方便地处理状态改变事件。 3. **绘制开关**...

    jquery 开关插件

    - **动画效果**:jQuery库提供了丰富的动画方法,如`fadeIn`、`fadeOut`等,可以为开关状态的切换添加平滑过渡效果。 - **可配置性**:优秀的开关插件会提供多种配置选项,让用户根据需求调整开关的行为和外观,如...

    自定义view_开关按钮

    这个过程涉及到的知识点包括但不限于:自定义View的创建、属性解析、视图绘制、触摸事件处理、动画实现以及状态保存与恢复。通过实践这些知识点,开发者可以创建出更符合应用需求的个性化用户界面。

    最完美的android仿ios开关按钮

    5. 状态保存与恢复:当应用被关闭或屏幕旋转时,Android会调用`onSaveInstanceState()`和`onRestoreInstanceState()`方法来保存和恢复组件的状态。为了保持开关按钮的状态,我们需要在此处处理。 6. UI适配:为了...

    基于STM32F103系列单片机,通过拨码开关,外部硬件设置PCB ID,带程序源码及原理图,C,C++源码.zip

    - 使用STM32F103的GPIO端口读取拨码开关状态,根据开关的开/关状态,将二进制数据存储在单片机的非易失性存储器中。 4. **源码解析** - C和C++源码:这些代码实现了读取拨码开关状态、转换为数字以及存储或显示...

    优盘usb写保护开关

    标题中的“优盘usb写保护开关”指的是USB闪存盘上的一个物理功能,它允许用户启用或禁用设备的写保护状态。写保护开关的主要目的是防止未经授权的数据修改或删除,同时也能有效地避免计算机病毒通过自动运行功能在...

    工控机读取板卡模拟量,开关量,输出开关量等,模拟量波形可以修改量程。

    工控机软件需要配置I/O端口,以监听或控制外部设备的开关状态。这可能包括设置中断服务程序,以响应来自PCI板卡的开关量变化。 "输出开关量"则是指工控机软件通过控制输出端口,驱动继电器或其他电子元件,实现对...

    自定义开关按钮控件

    这种组合可以轻松地模拟开关效果,因为开关通常只有开和关两个状态。 首先,我们需要了解RadioButton的基本用法。RadioButton是Android中的一个视图类,继承自CompoundButton,它提供了单选功能。我们可以通过设置...

    安卓android各种开关包括仿ios开关样式switchbuttondemo

    5. **状态保存与恢复**:为了保持应用在配置更改(如屏幕旋转)后开关状态的一致性,开发者需要实现`Parcelable`接口,以便在`onSaveInstanceState()`和`onRestoreInstanceState()`中保存和恢复开关的状态。...

Global site tag (gtag.js) - Google Analytics