文章标签 » javascript

发现一个好用的python版js压缩工具

https://github.com/rspivak/slimit
灰常好的工具,压缩比高,代码兼容性好,可媲美主流压缩工具~
做了下简单的benchmark:

#raw
256K jquery-1.8.1.js
#download from jquery.com
 92K jquery-1.8.1.min.js
 36K jquery-1.8.1.min.js.gz
#http://closure-compiler.appspot.com
 84K jquery-1.8.1.google.advanced.js
 32K jquery-1.8.1.google.advanced.js.gz
 92K jquery-1.8.1.google.simple.js
 36K jquery-1.8.1.google.simple.js.gz
#http://dean.edwards.name/packer
120K jquery-1.8.1.packer.js
 40K jquery-1.8.1.packer.js.gz
#http://refresh-sf.com/yui
#Uncaught SyntaxError: Unexpected token } 
 64K jquery-1.8.1.yui.js
 24K jquery-1.8.1.yui.js.gz
#slimit
 96K jquery-1.8.1.slimit.js
 36K jquery-1.8.1.slimit.js.gz

yui的虽然最nb,拉开其他工具一大截,但是压出来已经不能用了,难道是我点击提交按钮的方式不对??

实际使用时,我用的环境是redhat5.x,python环境较为恶劣,slimit只兼容到python 2.7,于是单独做了一个”便携版本”,可以兼容到2.4,并且相关依赖也放到一起,下载即用:)
https://github.com/emptyhua/js-css-minify-portable

node.js中mysql-native的掉线重联

由于受一篇性能测试的文章的影响,选择了mysql-native作为node的mysql客户端,由于没有自动重联的功能,长时间运行后就会掉线,所以加了一段判断掉线的代码:

var Mysql = null;
 
function MysqlConnect() { //... }
 
MysqlSafeQuery = function(sql) {
    if (!Mysql || !Mysql.connection.writable) {
        MysqlConnect();
    }
 
    return Mysql.query(sql);
}

JsonStream.js

JsonStream.js是一个用于node.js的双向通信协议实现,它使用json作为数据包格式,可以用于socket,也可以用于http长连接,同时自带了简单的rpc实现。这段代码现在被用于一个对实时性要求比较高的小项目,本来打算用python+twisted做,但是后来临时决定尝试一下node.js,下面举例说明用法:

第一个例子,最简单的应用,基于socket通信,发送和接受json数据
StreamServer.js

var Net = require('net');
var JsonStream = require('./JsonStream.js');
 
//创建一个普通的socket server
var server = Net.createServer(function(c) {
    //当有客户端连接后,socket连接之上创建一个JsonStream
    var stream = new JsonStream.Stream(c);
 
    //监听客户端发来的json数据
    stream.on('json', function(json) {
        console.log('receiv json from client:');
        console.log(json);
    });
 
    //没三秒钟向客户端发送一个json数据
    setInterval(function(){
        stream.write({
            data:'hello client',
            time:new Date()
        });
    }, 3000);
});
 
server.listen(7777);

第二个例子,基于socket,两端互相rpc调用
RpcServer.js

var Net = require('net');
var JsonStream = require('./JsonStream.js');
 
//定义服务端支持的Rpc接口
var ServerApi = {
 
    //这是一个普通的接口,直接返回数据
    hello:function(name) {
        console.log('client call hello');
        return 'hello ' + name;
    },
 
    //这是一个异步返回的方法
    //这里的SimpleDeferred的确不是一个全功能的Deffered
    //只能用在异步返回的情况
 
    helloAfter:function(name, delay) {
        console.log('client call helloAfter');
        var defer = new JsonStream.SimpleDeferred();
        setTimeout(function(){
            defer.done('hello ' + name + ' after ' + delay + 's');
        }, delay * 1000);
        return defer;
    }
};
 
var server = Net.createServer(function(c) {
    var stream = new JsonStream.Stream(c);
    stream.delegate = ServerApi;
 
    //每3秒调用一次客户端的say方法
    setInterval(function(){
        stream.rpcCall('say', ['你好!']);
    }, 3000);
});
 
server.listen(7777);

RpcClient.js中的调用部分

stream.rpcCall('hello', ['client a'], function(res) {
     console.log(res);
});
 
stream.rpcCall('helloAfter', ['client a', 1], function(res) {
     console.log(res);
});

第三个例子,用于长连接的http双向通信,由于客户端的代码和现有的业务框架结合比较紧密,暂不提供,只示意一下Server端的代码,基本使用方法和socket的类似

var Http = require('http');
var JsonStream = require('./JsonStream.js');
 
//Rpc接口定义
var ServerApi = {
};
 
//创建一个http server
var HttpServer = Http.createServer(function(request, response){
    //让JsonStream处理所有http请求
    JsonStream.HttpStream.acceptRequest(request, response);
});
 
JsonStream.HttpStream.events.on('new', function(stream, request) {
    console.log('new http stream !!!!!');
    stream.delegate = ServerApi;
    //发送json到浏览器端
    stream.write({
        data:'hello browser'
    });
});
 
HttpServer.listen(80);
//长连接的最大时长设为30秒
JsonStream.HttpStream.checkTimeOut(30);

更多细节详见源码:),经过一段时间的运行,代码已趋于稳定,可以通过svn获取代码和示例,请容忍我的不爱写注释,呵呵~:

http://code-of-emptyhua.googlecode.com/svn/trunk/nodejs/jsonstream

Hello lua

lua将作为下一门新语言学习。如果按照一年学习一门新语言的标准来说,我算超勤快的了。lua被发明的目的便是嵌入C或C++程序,给程序带来编译语言不及的灵活性。
google了一下lua,发现大部分都是做游戏开发的C++程序员的文章,看来不只是魔兽世界在用。

lua做嵌入的优势:
1 . 小,整个解释器不到200K
实际测试:
编译一个空的IOS项目 205K
嵌入Lua后的IOS项目 414K
2 . 运行速度快
实际测试:
做了三个测试程序,分别内嵌lua(静态链接),javascript(动态链接JavascriptCore,链接库6.4M),python(动态链接python2.6,链接库2.0M)
三个程序都做相同的事情,初始化一个脚本运行环境,打印一个字符串,销毁
比如lua,其他JS和python类似,只不过调用的api不一样:

static int lua_printf(lua_State *L)
{
    const char *cmsg = luaL_checkstring(L, 1);
    printf("%s\n", cmsg);
    return 0;
}
 
static void eval_lua(NSString *code)
{
    lua_State *L;
    L = lua_open();
    luaopen_base(L);
    lua_register(L, "printf", lua_printf);
    luaL_loadstring(L, [code cStringUsingEncoding:NSUTF8StringEncoding]);
    lua_pcall(L, 0, LUA_MULTRET, 0);
    lua_close(L);
}
 
int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
    NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
    eval_lua(@"printf(\"你好 lua\")");
    NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - start;
    printf("total time:%.5f\n", duration);
 
    [pool release];
    return 0;
}

PK结果

$ ls -lh *_test
-rwxr-xr-x  1 hualu  staff    10K  6 23 20:32 js_test
-rwxr-xr-x  1 hualu  staff   136K  6 23 20:37 lua_test
-rwxr-xr-x  1 hualu  staff   9.4K  6 23 20:32 py_test
$ ./lua_test
你好 lua
total time:0.00018
$ ./js_test
你好 Javascript
total time:0.00557
$ ./py_test
你好 Python
total time:0.01311

3. lua支持多线程,每个线程可以配置独立的解释器(没有亲测,道听途说)
4. 语法简单,其实这个可以算优点,比JS要简单易懂的多。。。

lua这么小巧的身躯太适合嵌入手机软件了。可以动态的从server上加载一些lua脚本来运行,免去劳烦用户更新软件的烦恼~.就目前所知,愤怒的小鸟是一个混合编程的好例子,关卡的设置均由lua控制。

其实已经有geek为前面三门语言做了Objc的Bridge,项目分别是:
对于lua有wax
对于js有jscocoa
对于python有PyObjc

而且他们的目的已经不是简单的嵌入Objectivc了,而是代替objc作为MAC或IOS应用的开发语言。。。当然我并不是很赞同这种偷懒的方法,脚本要适度使用。

最后,看的一些资料:
Lua 5.1 参考手册
xcode中添加静态链接库
lua和python谁更适用于嵌入MMORPG?

关于js的字符串编码

The String type is the set of all finite ordered sequences of zero or more 16-bit unsigned integer values (“elements”). The String type is generally used to represent textual data in a running ECMAScript program, in which case each element in the String is treated as a code unit value (see Clause 6). Each element is regarded as occupying a position within the sequence. These positions are indexed with nonnegative integers. The first element (if any) is at position 0, the next element (if any) at position 1, and so on. The length of a String is the number of elements (i.e., 16-bit values) within it. The empty String has length zero and therefore contains no elements.
When a String contains actual textual data, each element is considered to be a single UTF-16 code unit. Whether or not this is the actual storage format of a String, the characters within a String are numbered by their initial code unit element position as though they were represented using UTF-16. All operations on Strings (except as otherwise stated) treat them as sequences of undifferentiated 16-bit unsigned integers; they do not ensure the resulting String is in normalised form, nor do they ensure language-sensitive results.

按照ECMA标准,无论引擎底层如何实现,js的字符串看起来都应该是UTF-16编码的字符串,并且每个字符串单元代表一个UTF-16的双字节
例如:
>”中”.length
1
(不知道这是啥特殊字符,发到wordpress有问题,直接贴图,那我是怎么输进去的呢,后面说转义符)
“中”编码成UTF-16为一个双字节0x4E2D,所以长度为1
长的像口的字符编码成UTF-16占4字节 0xD950 0xDF21,占用两个双字节,长度为2
(下面用”口”代替这个特殊字符)
>”口”[0]
“”
>”口”.charCodeAt(0).toString(16)
“d950”
所以字符串的长度显然是占用双字节的个数,而非我以前想当然认为的实际字符的个数。。。

\udddd形式的转义同样用来表示一个双字节,而非字符本身,”口”用转义符来表示的话:

最后我要的结论是:

对于像objective c里unichar一样的UTF-16编码格式的字符串可以通过@“\\u04x”直接得到json转义串~