随笔-57  评论-129  文章-0  trackbacks-0
 
如题:
JSA介绍:http://www.javaeye.com/article/77776
posted @ 2007-06-05 18:34 金大为 阅读(293) | 评论 (4)编辑 收藏
JSI2 Alpha即将发布,关于两类特殊文件的命名方式,想听听大家的建议:

包定义文件,原先为 __$package.js
  缺点:$符号再linux上处理有点麻烦,通过shell命令创建时需要使用转义字符(\$)

预装载缓存脚本(编译结果,用于支持延迟同步非阻塞式装载),原先与原文件同名,只是映射到其他目录.
  缺点:同一个包的资源处在不同目录,发布,部署都有点麻烦.


现在的修改想法:

方式一:

__[package].js
file.js
file[preload].js

缺点:[]也算特殊字符.
优点:看起来比较直观,也不容易和已有文件冲突.linux系统中,通过控制台还是可以直接创建的,不用转义.

方式二:

__package__.js
file.js
file__preload__.js

缺点:看起来没有上面的直观.已有别的类库采用这个名字,不便于编辑工具识别 .
优点:无特殊字符.

大家感觉如何?给点建议吧:)
posted @ 2007-06-03 14:31 金大为 阅读(618) | 评论 (3)编辑 收藏
    JSI是一个简单、无侵入(被管理的脚本无需考虑JSI的存在)的脚本管理框架, JSI的出现,可以做到如下几点:

* 按需装载。
* 管理依赖,避免依赖的保露、扩散,提高类库的易用性。
* 执行环境的隔离,避免名称冲突。

类库装载

    动态装载类库是按需装载的基础,JSI的装载方式有三种:即时同步装载(可能阻塞)、延迟同步装载(需要编译)、异步装载。这里先演示一下最简单的方式,即时同步导入:

示例:重写一下jQuery的hello world。
….
<!-- 加入引导脚本 -->
<script src="../scripts/boot.js"></script>
….
<script>
//导入jQuery的$函数
$import("org.jquery.$");
//使用jQuery的$函数
$(document).ready(function(){
  alert(
"Hello World");
 });
</script>
….

    这是默认的导入方式,当能,如果网络环境不好,这可能产生阻塞问题。所以JSI2开始增加了仍外两种导入模式。延迟同步导入,异步导入。具体用法请查看文章后面的导入函数参考。

依赖管理

    Java可以随意的使用第三方类库,可是JavaScript却没那么幸运,随着类库的丰富,烦杂的依赖关系和可能的命名冲突将使得类库的发展越来越困难。程序的易用性也将大打折扣。

    命名冲突的危险无形的增加你大脑的负担;随着使用的类库的增加,暴露的依赖也将随之增加,这是复杂度陡增的极大祸根,将使得系统越来越复杂,越来越难以控制。潜在的问题越来越多,防不胜防。

    所以,我们建议类库的开发者将自己类库的依赖终结在自己手中,避免依赖扩散,以提高类库的易用性。

    为了演示一下JSI的依赖管理,我们编写一个复杂一点的类库:类似Windows XP文件浏览器左侧的滑动折叠面板(任务菜单)效果。

1.编写我们的折叠面板函数(org/xidea/example/display/effect.js):
/**
 * 滑动面板实现.
 * 当指定元素可见时,将其第一个子元素向上滑动至完全被遮掩(折叠)。
 * 当指定元素不可见时,将其第一个子元素向下滑动至完全显示(展开)。
 
*/
function slidePanel(panel){
  panel 
= $(panel);
  
if(panel.style.display=='none'){
    
//调用Scriptaculous Effect的具体滑动展开实现
    new Effect.SlideDown(panel);
  }
else{
    
//调用Scriptaculous Effect的具体滑动闭合实现
    new Effect.SlideUp(panel);
  }
}

2.编写包定义脚本,申明其内容及依赖(org/xidea/example/display/__$package.js):
//添加slidePanel(滑动面板控制)函数
this.addScript("effect.js","slidePanel",null);
//给effect.js脚本添加对us.aculo.script包中effects.js脚本的装载后依赖this.addScriptDependence("effect.js",
"us/aculo/script/effects.js",false);
//给effect.js脚本添加对net.conio.prototype包中$函数的装载后依赖this.addScriptObjectDependence("effect.js",
"net.conio.prototype.$",false);

3.HTML代码:
<html>
  
<head> 
  
<title>重用aculo Effect脚本实例</title>
  
<link rel="stylesheet" type="text/css" href="/styles/default.css" />
  
<script src="/scripts/boot.js"></script>
  
<script>
    $import(
"org.xidea.display.slidePanel");
  
</script>
  
</head>
  
<body>
    
<div class="menu_header"
        onclick
="slidePanel('menu_block1')">
        面板 1
    
</div>
    
<div class="menu_block" id="menu_block1">
      
<ul>
        
<li>text1</li>
        
<li>text2</li>
        
<li>text3</li>
      
</ul>
    
</div>
</body>
</html>

    onclick="slidePanel('menu_block1')"这个事件函数将在我们点击面板标题时触发,能后会调用Scriptaculous Effect的具体实现去实现我们需要的滑动折叠功能。

    这个效果只是八行代码,比较简单,但是它用到了Scriptaculous Effect类库,Scriptaculous Effect又简接用到了Prototype类库,所以,传统方式使用起来还是比较复杂,有一堆脚本需要导入prototype.js,effects.js,builder.js,更加痛苦的是这些脚本的导入还要遵守一定的顺序。

    但是,如果我们使用JSI 明确申明了这些依赖,那么使用起来就简单多了,只一个import就可以完全搞定。
    此外 这里还有一个额外的好处,我们类库中依赖的那些脚本,并不会对外部保露,在页面上是不可见的,也就是说,这些依赖完全终结在刚才编写的类库中,不必担心使用这些类库带来的名称污染问题。


环境隔离

    众所周知, Scriptaculous所依赖的Prototype库与jQuery存在冲突。所以同时使用比较困难。
    下面的例子,我们将在同一个页面上同时使用Scriptaculous和 jQuery 类库。示范一下JSI隔离冲突功能。
示例页面(hello-jquery-aculo.html):
<html>
<head>
<title>Hello jQuery And Scriptaculous</title>
<!-- 加入引导脚本 -->
<script src="../scripts/boot.js"></script>
<script>
//导入jQuery
$import("org.jquery.$");
//导入Scriptaculous
$import("us.aculo.script.Effect");

$(document).ready(
function(){
  
//使用jQuery添加一段问候语
  $("<p id='helloBox' style='background:#0F0;text-align:center;font-size:40px;cursor:pointer;'>\
Hello jQuery And Scriptaculous</p>
")
    .appendTo('body');
  $('#helloBox').ready(
function(){
    
//使用Scriptaculous高亮显示一下刚才添加的内容
    new Effect.Highlight('helloBox');
  }).click(
function(){
    
//当用户单击该内容后使用jQuery实现渐出
    $('#helloBox').fadeOut();
  });
 });
</script>
</head>
<body>
<p>文档装载后,jQuery将在后面添加一段问候语;并使用Scriptaculous高亮显示(Highlight);在鼠标点击后在使用jQuery渐出(fadeOut)。</p>
</body>
</html>




其他话题

    JSI组件模型:
    页面装饰引擎:用于装饰朴素html元素的框架,实现零脚本代码的web富客户端编程,更多细节请访问jsi官方网站。


参考:

    脚本导入函数
    脚本导入函数是JSI唯一的一个在页面上使用的系统函数。

  function $import(path, callbackOrLazyLoad, target )
      path 类库路径
      callbackOrLazyLoad 可选参数,如果其值为函数,表示异步导入模式;如果其值为真,表示延迟同步导入模式,否则为即时同步导入(默认如此)。
      Target 可选参数(默认为全局变量,所以说,这种情况等价于直接声明的全局变量),指定导入容器。
名词解释:
    * 自由脚本
通过<script>标记引入或直接编写的脚本,我们不建议在使用JSIntegration之后,仍旧使用script src导入JSI启动脚本(boot.js)之外的脚本。
    * 托管脚本
通过$import函数直接或间接加载的脚本。这些脚本将在一个独立的执行上下文装载,不会污染全局环境。
    * 脚本依赖
若要使用A,需要导入B,则A依赖B。
A、B可以是脚本文件,也可以是脚本文件中的某个脚本元素。
    * 类库使用者
类库的使用者,您只需再页面上书写脚本,导入类库,编写自己的简单脚本,一般情况请不要编写js文件,那是类库开发者做的事.
    * 类库开发者
在此框架下开发出方便实用的脚本库,您需要编写一些通用脚本,同时设置脚本依赖,做到任何类/函数,导入即可运行。


posted @ 2007-06-02 14:16 金大为 阅读(1606) | 评论 (0)编辑 收藏
先申明一下,我讨厌Ajax这个名词。旧药装新瓶。(像那个80来岁的杨某一样令人讨厌,呵呵)。

正题:

    Ajax所谓的异步加载,为何需要异步,可以说异步操作通常都是一个成熟的程序设计人员会尽力回避的东西。复杂度徒增,不好控制,容易出错。

    但是,这个问题放在浏览器上就是另外一个情形,浏览器上的脚本+事件通常只有一个线程。那些看是多线程的函数:setTimeout, setInterval,其实都不会插入或中断任何一个其他的在执行中的任务,而且一旦你的脚本尚在运行,那么不管你是否在挂起等待,所有的事件都将阻 塞。窗口重画,拖动...也都得靠边站着,感觉就像是某个程序进入一个死循环了。

    以前得脚本都是做一些简单得事情,需要的时间,用户基本上都感觉不到,后来XMLHttpRequest的兴起,问题出来了,访问网络资源,你得受网速得 限制,如果同步的获取,那你就等吧,等个几秒几分几十分的,不是不可能。这时浏览器可没那么聪明,站旁边傻等,什么窗口重画,移动啊,都装个没听见。

    浏览器傻了,用户可不傻,靠,这个网站咋的,吧我的浏览器都搞死了?加入黑名单,或者碰到个脾气好点的,把你辛辛苦苦、没日没夜、绵绵数月敲下来的脚本,一律禁止运行... 傻了把,可怜的脚本程序员。

    看似浏览器的问题嘛,可是,谁叫你是中年诸葛亮呢,扶不起的阿斗你也得背着,朽木上刻章方显你的出众嘛。于是异步操作遍地开花,第N次世界大乱从此开始。

    确实这里使用异步操作很有见成效,先告诉xmlhttp后台加载网络资源。一边凉快凉快,加载完了通知一下。喝喝茶,看看报,N+1秒钟过去了,报告: 001.xml全体元素集合完毕,帐前待命...,ok,..... (机密,隐藏...)。

    不错把,你不必焦急的盯着屏幕上所不期望的白大块,不用使劲的失望的拖动着没有的鼠标。你只需要东瞧瞧西瞅瞅,随意的打发点时间,一会,东西准备好了,归你了,爱怎么办就怎么办吧。

    没看明白?简单点说吧,就是把资源加载这一操作放在脚本线程之外,那么就不会有长时间运行的脚本,那么用户就觉得你的程序响应快。就是是说ajax,其实asynchronism也就这一个地方而已。

    记住一点,浏览器上单纯的脚本程序,本身是不支持多线程的,异步也就无从谈起,而现在所说的异步,都不是纯粹的ECMAScript,都是利用浏览器带有的某些原生对象实现的。

    雕虫小技而已,结果吹得鸡毛满天飞。众嘴纭纭之势,众目睽睽之下,公鸡下蛋,鲤鱼上坡,皆有可能。
posted @ 2007-06-02 14:11 金大为 阅读(951) | 评论 (13)编辑 收藏
循环反转示例:

  for(var i = 0;i<data.length;i++){
    
//.
  }
  
//反转后代码
  for(var i = data.length-1;i>=0;i--){
    
//.
  }

这类优化的作用是明显的,但是具体有多大作用呢?

用一个长度为100 000 的数组测试一下:
515/313
500/313
516/312
516/328
516/328

可见,循环反转后,只需要原来3/5的时间.
但是,这种东西到底有多大价值?FF上200次循环仅需要1毫秒的时间.所以,个人认为,只要循环的内容不是太长,使用不算非常频繁,那么没有太大必要.
加入循环的长度需要通过函数取得,且不变,那么,反转的效率还是可观的,在IE上,函数调用消耗是普通操作的十多倍.

测试代码:
var incTime = 0;
var decTime = 0;
var inc = 0;
var data = new Array(10*10000);
//while(inc++<50)
{
  
var t1 = new Date();
  
for(var i = 0;i<data.length;i++){
  }
  
var t2 = new Date();
  
for(var i = data.length-1;i>=0;i--){
  }
  
var t3 = new Date();
  incTime
+=(t2-t1);
  decTime
+=(t3-t2);
}

prompt(
"incTime/decTime",incTime +'/'+decTime)


posted @ 2007-05-31 12:30 金大为 阅读(891) | 评论 (5)编辑 收藏
JSI的实现中,有这样一种需求,将有自带命名空间的脚本元素名数组转换成没有命名空间的变量名数组.
比如 :
['YAHOO.util.XXXX,YAHOO.util.YYYY,YAHOO.event.XX'] ->['YAHOO']

以前一直是较长的一段处理代码,今天突发奇想,这个用正则表达式处理效果如何?

于是,就这种处理,分别测试了正则表达式和javascript代码的效率.

测试数据如下(regTime /codeTime):
620/4536
729/4068
719/4250
645/4152
655/4642

FF和IE结果差不多,上面是FF2的数据

总结:
经常看见很多地方对正则表达式的效率的怀疑,但是这个问题放在javascript里面,好像情况又不同了. 适当使用正则式,反而可以大大提高效率.
在javascript这类\较慢的解释型语言里面,少即快,能用原生代码就不要自己写.

测试代码:
var data = [];
for(var i = 0;i<20;i++){
  data[i] 
= "NS"+i/10+'.'+i
}
document.write(
  
//(data == data.sort()) +"/"+
  data +"<hr>")
var i = 0;
var regTime = 0;
var codeTime = 0;
var inc = 0;
var reg = /(\b[\$\w]+)[\$\w\.]*(,\1\b[\$\w\.]*)*/g;

var regResult,codeResult;
while(inc++<100){
  
var i=0;
  
var t1 = new Date();
  
while(i++<100){
    regResult 
= data.join(',').replace(reg,'$1').split(',');
  }

  
var t2 = new Date();
  
while(i++<200){
    codeResult 
= [];
    
var flagMap = {};
    
for(var j=data.length-1;j>=0;j--){
      key 
= data[j];
      key 
= key.substr(0,key.indexOf('.'));
      
if(!flagMap[key]){
        codeResult[codeResult.length] 
= (key);
        
//codeResult.push(key);
        flagMap[key] = true;
      }
    }
  }
  
var t3 = new Date();
  regTime 
+=(t2-t1);
  codeTime
+=(t3-t2);
}
document.write(
  
"regResult:"+
  regResult)
document.write(
  
"<hr>codeResult:"+
  codeResult)
prompt(
"regTime /codeTime",regTime  +'/'+codeTime)

posted @ 2007-05-30 13:22 金大为 阅读(894) | 评论 (0)编辑 收藏
一直都认为,javascript的函数调用是一个相对耗时的操作。
开始JSI的优化,这些问题现在必须认真考虑了,测试一把:

一个简单的++操作,直接操作和函数内操作(注,函数参数对原始类型是值传递,所以这不会影响被传入的变量,这里测试里面,两类操作的行为是不一样的)

FF2测试结果(callTime/opTime):
2871/2582
2919/2675
2734/2704
2953/2516
3732/3346

IE7测试结果:
3140/376
3173/327
3238/247
3265/235
3217/299

通过测试可见,函数调用的消耗基本可以忽略。每次调用时间仅为:
3000/(200*1000*5) ==0.3毫秒 ,这个时间还包含函数内部的++操作

从示例可见,FF的函数调用消耗基本可以府略,IE虽然相当于十倍++类简单操作,但依然不足以重视。

奇怪的是,第一次碰见ie的运行效率高于ff的情况。

测试代码
var i = 0;
var callTime = 0;
var opTime = 0;
var inc = 0;
function plus(z){z++};
while(inc++<200){
  
var i=0;
  
var x = 1;
  
var t1 = new Date();
  
while(i++<1000){
    plus(x);
    plus(x);
    plus(x);
    plus(x);
    plus(x);
  }

  
var t2 = new Date();
  
while(i++<2000){
    x
++;
    x
++;
    x
++;
    x
++;
    x
++;
  }
  
var t3 = new Date();
  callTime
+=(t2-t1);
  opTime
+=(t3-t2);
}

prompt(
"callTime/opTime",callTime +'/'+opTime)





posted @ 2007-05-29 18:00 金大为 阅读(904) | 评论 (0)编辑 收藏
前几天无意中看到一个网友blog上关于这个循环效率的问题,说要尽量避免使用。
有点害怕,我在JSI中可是用了不少,呵呵。
测试一下,负担终于可以放下来了:

测试对象:
一个对象模拟map,测试for in 循环
两个数组,测试for(;;)循环

连续4次运行时间比。
957/1278;955/1357;1014/1282;968/1392


明显,要实现类似map的功能,还是for in 快点。

上面的数据是ff2上的结果,ie7上也差不多,差距更小一点。

测试代码:
function C(i){
  
return i<62?
    String.fromCharCode(i
+=
      i
<26?65
        :i
<52?71//97-26
          :-4//48-26-26
    )
      :i
<63?'_'
        :i
<64?'$'
          :C(i
>>6)+C(i&63)
}
var map = {};
var arr1 = [];
var arr2 = [];

for(var i = 0;i<1000;i++){
  
var c = C(i);
  map[c] 
= i;
  arr1.push(c);
  arr2.push(i);
}
var i = 0;
var mapTime = 0;
var arrTime = 0;
var inc = 0
while(inc++<500){
  
var t1 = new Date();
  
for(var n in map){
    n 
= map[n];
  }
  
var t2 = new Date();
  
for(var j = 0;j<1000;j++){
    n 
=arr1[j];
    n 
=arr2[j];
  }
  
var t3 = new Date();
  mapTime
+=(t2-t1);
  arrTime
+=(t3-t2);
}

prompt(
"mapTime/arrTime",mapTime +'/'+arrTime)


posted @ 2007-05-27 17:18 金大为 阅读(1463) | 评论 (13)编辑 收藏
无赖,自己外语太差,就算想去也难办,呵呵。

怀疑 sourceforge是不是在搞贩人服务呢?

posted @ 2007-05-27 10:36 金大为 阅读(128) | 评论 (0)编辑 收藏
刚刚修正了一个JSA的bug。

顺便测试了一下文本压缩的性能,和纯packer 压缩,ShrinkSafe+packer压缩。
压缩大小:
jquery-jsa-s.js(JSA的语法压缩):29766
jquery.compressed.js(ShrinkSafe语法压缩):33992

jquery-jsa-st.js(JSA的语法压缩+文本压缩):19526
jquery-packer.js(Packer文本压缩):20977
jquery.compressed-packer.js(ShrinkSafe语法压缩+Packer文本压缩):21839

有点奇怪的是,文本压缩和语法压缩是有一定互补性的,但是ShrinkSafe+Packer比单纯的Packer文本压缩效率还低??
我想可能是ShrinkSafe做的一些语法补全(可省略的 {、}、;、),jQuery编码的风格导致。

Firefox测试数据(10次压缩时间的毫秒数,连续5回测试数据)

jquery-jsa-st.js:784
jquery-packer.js:1265
jquery.compressed-packer.js:1529

jquery-jsa-st.js:718
jquery-packer.js:922
jquery.compressed-packer.js:766

jquery-jsa-st.js:753
jquery-packer.js:872
jquery.compressed-packer.js:828

jquery-jsa-st.js:1438
jquery-packer.js:1484
jquery.compressed-packer.js:1735

jquery-jsa-st.js:687
jquery-packer.js:1236
jquery.compressed-packer.js:1234


IE5 测试数据(连续三回测试数据)

jquery-jsa-st.js:766
--------------------------------------------------------------------------------
jquery-packer.js:9765
--------------------------------------------------------------------------------
jquery.compressed-packer.js:10547


jquery-jsa-st.js:671
--------------------------------------------------------------------------------
jquery-packer.js:9002
--------------------------------------------------------------------------------
jquery.compressed-packer.js:10265


jquery-jsa-st.js:704
--------------------------------------------------------------------------------
jquery-packer.js:8232
--------------------------------------------------------------------------------
jquery.compressed-packer.js:10314

总结

文本压缩是个比较耗时的操作,像JQuery这样大的类库普遍需要接近100毫秒的解压时间。
如果需要兼容IE5这种老古董,那么最好不要用packer的文本压缩,太耗时。
JSA1 对文本压缩做了些改进,表现还可以。

如果要计较脚本文本压缩后的解压开销,建议使用JSA的语法压缩,配合服务器端的gzip压缩。
不推荐dojo 的ShrinkSafe,原因是它的几个安全问题。
posted @ 2007-05-24 09:28 金大为 阅读(937) | 评论 (0)编辑 收藏
仅列出标题
共6页: 上一页 1 2 3 4 5 6 下一页