2007-11-09
如何在JavaScript中实现某个方法执行超时后则继续执行其它方法?
关键字: 方法 执行 超时 settimeout setinterval
我的一个想法是这样的,如下代码:
异想天开,想用 setTimeout 来做个 workaround ,但是 setTimeout / setInterval 方法是在它所在的方法执行完之后才开始计时的,于是,光当一声,这个 workaround 不成立。
各位有没有做过类似的需求,如何解决的呢?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JavaScript方法执行超时测试</title>
<script>
var executed = false; // 方法B是否执行的标志位
var x = 0; // 方法A中用来累加计数,使方法A执行超时
var expiredTime = 3000;
// 方法A
function methodA( )
{
// 第一句就执行定时器
setTimeout("methodB()",expiredTime);// setInterval()
// 方法A的耗时内容执行开始
x = x + 1;
document.counter.displayBox.value = x;
for(i = 0;i < 80000;i++)
{
window.status = "i=" + i;
}
// 方法A的耗时内容执行结束
// 当方法A的耗时内容没有超过expiredTime的时间执行完成的话,就直接开始执行方法B
methodB();
// 设置方法B执行完成的标志位
executed = true;
}
// 方法B
function methodB()
{
if(executed == true)
{
// 执行过了......
}
else
{
// 执行......
}
}
</script>
</head>
<body>
<form name="counter">
<input type="text" name="displayBox" value="0" size="10"/>
</form>
<script>
methodA();
</script>
</body>
</html>
异想天开,想用 setTimeout 来做个 workaround ,但是 setTimeout / setInterval 方法是在它所在的方法执行完之后才开始计时的,于是,光当一声,这个 workaround 不成立。
各位有没有做过类似的需求,如何解决的呢?
评论
andyhu1007
2008-07-03
afcn0 写道
首先js是单线程的,lz的想法就不对,那是多线程,现在基本除了XHR的callback可以另开一个线程以外,还无法实现多线程,其次timeout是在本次js代码运行完开始计时timeout的,所以在一个耗时的函数之外timeout或者interval一个函数运行本身就是荒谬的,ie下面alert,js函数执行也会阻塞interval执行,应该其他浏览器也是这么实现,我没测试,如果interval可以实现多线程,那至少ie上面也不行
js是单线程的没错,但是setTimeout确实可以解决这个问题。因为IE识别javascript是否running过长,是对每个event触发的javascript method而言。所以,分离出独立的方法,用setTimeout触发,确实可以让IE不要跳出那个可恶的error。当然,本质上没有减少运行的总体时间。
xqstation
2008-06-12
貌似你执行某个方法 fun1();
估计其应该只执行30秒,如果超了。这个方法结束。执行另一个方法?
但是fun1还是在执行啊。
并且IE会挂掉的。。。
估计其应该只执行30秒,如果超了。这个方法结束。执行另一个方法?
但是fun1还是在执行啊。
并且IE会挂掉的。。。
cbhyk
2007-11-13
一切都是因为Windows程序是消息驱动的,看以下Windows程序的代码:
一个Windows程序的入口是WinMain,这里面主要部分就是一个消息循环。IE用window.open的时候没有创建新进程,所以所有的消息都是主窗口的消息处理循环在处理。IE打开一个新窗口的时候所做的事情大概就是CreateWindow、ShowWindow、UpdateWindow,这三个方法里面并不是直接显示新窗口,而时往消息队列里面放WM_SHOW、WM_PAINT等消息,要到主消息循环处理到这些消息时才显示新窗口。
另外,setTimer,setInterval也只是让系统在若干时间后放一个WM_TIMER消息到消息队列,主消息循环处理到这个消息时才会运行setTimer和setInterval时指定的回调函数。
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLAS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuNam = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow( szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ; // Post Message WM_SHOW
UpdateWindow (hwnd) ; // Post Message WM_PAINT, 这里可能不对
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE:
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, TEXT ("Hello, World!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
一个Windows程序的入口是WinMain,这里面主要部分就是一个消息循环。IE用window.open的时候没有创建新进程,所以所有的消息都是主窗口的消息处理循环在处理。IE打开一个新窗口的时候所做的事情大概就是CreateWindow、ShowWindow、UpdateWindow,这三个方法里面并不是直接显示新窗口,而时往消息队列里面放WM_SHOW、WM_PAINT等消息,要到主消息循环处理到这些消息时才显示新窗口。
另外,setTimer,setInterval也只是让系统在若干时间后放一个WM_TIMER消息到消息队列,主消息循环处理到这个消息时才会运行setTimer和setInterval时指定的回调函数。
YuLimin
2007-11-12
感谢这么多人的热烈讨论,下面的代码是我继原贴后写的测试代码,大家可以在IE、FireFox、Opera等浏览器里测试一下看看结果。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JavaScript方法执行超时测试</title>
<script>
var executed = false; // 方法B是否执行的标志位
var x = 0; // 方法A中用来累加计数,使方法A执行超时
var expiredTime = 2000;
function methodMain()
{
expiredTime = 1000 * document.counter.expiredTime.value;
var t = setInterval("methodA()",0);// setInterval()
//clearTimeout
setInterval("methodB()",expiredTime);// setInterval() setTimeout
//clearInterval
}
// 方法A
function methodA()
{
// 记下methodA执行的开始时间
document.counter.aBegin.value = getNow();
var loopSize = document.counter.loopSize.value;
// 方法A的耗时内容执行开始
for(i = 0;i <= loopSize;i++)
{
document.counter.displayBoxA.value = "i=" + i;
}
// 方法A的耗时内容执行结束
// 当方法A的耗时内容没有超过expiredTime的时间执行完成的话,就直接开始执行方法B
methodB();
// 设置方法B执行完成的标志位
executed = true;
// 记下methodA执行的结束时间
document.counter.aEnd.value = getNow()
}
// 方法B
function methodB()
{
// 记下methodB执行的开始时间
document.counter.bBegin.value = getNow();
if(executed == true)
{
// 执行过了......
// document.counter.displayBox.value = '执行过了......';
}
else
{
for(var i = 0;i < 100;i++)
{
x = x + 1;
document.counter.displayBoxB.value = x;
}
}
// 记下methodB执行的结束时间
document.counter.bEnd.value = getNow()
}
function getNow()
{
var now = new Date();
var year = now.getYear();
var month = now.getMonth();
var day = now.getDay();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
// return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
return new Date().format("yyyy-MM-dd hh:mm:ss");
}
Date.prototype.format = function(format)
{
var o =
{
"M+" : this.getMonth()+1, //month
"d+" : this.getDate(), //day
"h+" : this.getHours(), //hour
"m+" : this.getMinutes(), //minute
"s+" : this.getSeconds(), //second
"q+" : Math.floor((this.getMonth()+3)/3), //quarter
"S" : this.getMilliseconds() //millisecond
}
if(/(y+)/.test(format))
format = format.replace(RegExp.$1,(this.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(format))
format = format.replace(RegExp.$1,RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
return format;
}
// alert(new Date().format("yyyy-MM-dd hh:mm:ss"));
</script>
</head>
<body>
<form name="counter">
方法A执行的开始时间:<input type="text" name="aBegin" value="" size="30"/><br/>
方法A执行的结束时间:<input type="text" name="aEnd" value="" size="30"/><br/>
方法A计数器:<input type="text" name="displayBoxA" value="0" size="20"/><br/>
方法A执行的超时限制时间:<input type="text" name="expiredTime" value="2" size="30"/>秒<br/>
方法A中用来模拟执行的死循环大小:<input type="text" name="loopSize" value="5000" size="30"/>次<br/>
方法B执行的开始时间:<input type="text" name="bBegin" value="" size="30"/><br/>
方法B执行的结束时间:<input type="text" name="bEnd" value="" size="30"/><br/>
方法B计数器:<input type="text" name="displayBoxB" value="0" size="20"/><br/>
<p> </p>
执行测试:<input type="button" name="exe" value="开 始" onclick="methodMain();"/>
<input type="reset" name="tReset" value="重 置"/>
</form>
</body>
</html>
afcn0
2007-11-12
不是很理解hax写的,window.open我是这样测试的
a.htm
b.htm
经测试ff ie均表示open不用等待窗口load完毕继续执行下面代码,和XHR的异步差不多,并且open的窗口不是立即执行,而是等待主窗口js停止执行后才进行load动作,所以看到是先有aaaaa字符,后有hr的横线,open好似只是注册一个要打开的窗口,而不是立即执行,有点timeout意思
a.htm
<div id="test">
</div>
<script>
setTimeout(function(){
eee=window.open("b.htm");
var temp=new Date().getTime();
for (var i=0; i<100000; i++ )
{
if(window.t)
{
document.getElementById("test").innerHTML="thread2 run";
}
i=i+10000;
i=i-10000;
}
document.getElementById("test").innerHTML+=new Date().getTime()-temp;
document.documentElement.appendChild(document.createTextNode("aaaaaaaaaa"));
//ie document.body.innerHTML+="aaaaaa"
},0)
</script>
b.htm
<div id="test"></div>
<script>
window.opener.document.documentElement.appendChild(document.createElement("hr"));
//ie window.opener.document.body.innerHTML+="<hr>"
</script>
经测试ff ie均表示open不用等待窗口load完毕继续执行下面代码,和XHR的异步差不多,并且open的窗口不是立即执行,而是等待主窗口js停止执行后才进行load动作,所以看到是先有aaaaa字符,后有hr的横线,open好似只是注册一个要打开的窗口,而不是立即执行,有点timeout意思
hax
2007-11-12
myy 写道
据我所知,IE6 (IE7标签页方式不清楚) 用 open(), _balnk, Ctrl+N 等各种方式打开的新窗口都是在独立的线程中运行的,并且同时都属于一个IE进程,"浏览器的主线程"这种说法也不确切,事实上,同一个IE进程每个IE窗口线程都是平等的,根本没有哪个是"主线程"之说。也就是说,每个IE窗口线程中都有"全套"的东西,包括 js引擎。(不过,底层的网络通讯采用了线程池,这个是共享的)。
这样,虽然"JS本身一定是单线程的",但是open()创建了两套"在不同线程中的js引擎环境",通过这样来模拟 LZ 的要求是可行的。
首先open,ctrl-n出来的窗口,与原窗口肯定同属一个进程。你用桌面图标启动的新的IE窗口就在另外一个进程里,那不在我们的讨论范围之内。其次,你说它们都在独立的窗口线程里,maybe。但我指的是主线程,就是浏览器的主控线程,其他线程都是从这个线程上分支出来的。当然,偶不清楚IE内部构造到底是如何的。但是一个IE窗口不应该有全套的东西,否则就变成一个独立的进程了。而且即使每个窗口都一个独立的js引擎,其执行也是线性化的。这很容易推理出来,因为一个窗口的脚本可以调用另一个窗口的脚本,也就是一个窗口的脚本一定可以阻塞另一个窗口的脚本。这就是我为什么说窗口对于脚本来说没有意义的原因。
测试代码:
<html>
<head>
<title>Test JS thread</title>
<script>
function heavyWork(size) {
info('Start a heavy work...');
size = size || 1000;
var result = 0;
for (var i = 0; i < size; i++) {
for (var j = 0; j < size; j++) {
result += Math.random();
}
}
info('Done.');
}
function test() {
window.open('test.html', '_blank', '');
heavyWork();
}
function info(msg) {
var now = new Date().getTime() % 100000;
document.getElementById('info').innerHTML += '[' + now + '] ' + msg + '<br>';
}
window.onload = function () {
info('loaded.');
heavyWork();
}
</script>
</head>
<body>
<div id="info">
loading...<br>
</div>
<div>
<button onclick="test()">Open a new window with a heavy work</button>
</div>
</body>
</html>
hax
2007-11-12
afcn0 写道
补充个测试
opera ie ff上面都没有显示thread2 run所以基本肯定js就是单线程的
opera ie ff上面都没有显示thread2 run所以基本肯定js就是单线程的
养成写测试的习惯是很好的!事实胜于雄辩。
fins
2007-11-12
新开窗口的呢??
afcn0
2007-11-12
补充个测试
opera ie ff上面都没有显示thread2 run所以基本肯定js就是单线程的
<div id="test">
</div>
<script>
function aaa(){
var temp=new Date().getTime();
for (var i=0;i<10000 ;i++ )
{
if(window.t)
{
document.getElementById("test").innerHTML="thread2 run";
}
i=i+10000;
i=i-10000;
}
document.getElementById("test").innerHTML+=new Date().getTime()-temp;
return i;
}
function bbb(){
t=1234;
}
setTimeout(aaa,5);
setTimeout(bbb,10);
</script>
opera ie ff上面都没有显示thread2 run所以基本肯定js就是单线程的
afcn0
2007-11-12
没有过多分析,只是思维上的猜测,window.open必须等待打开页面onload彻底执行完才返回,所以和原页面是单线程(此点有待实验证实),但是即便如此setTimeout可以注册在load事件后执行,所以应该可以实现多窗口多js并行
timeout interval应该看js解释器是如何实现的,比如ie就永远是单线程,alert都会终止timer的计时,但是其他解释器则不然,所以至少ie上面是没有多线程一说的,也许ff或其他确实可以实现多timer并行执行(没测试),但是还是那句话,ie不支持也是有其道理的,不要把web弄的太复杂了
...我一个菜鸟被楼上大哥称为大牛,烧的难受
timeout interval应该看js解释器是如何实现的,比如ie就永远是单线程,alert都会终止timer的计时,但是其他解释器则不然,所以至少ie上面是没有多线程一说的,也许ff或其他确实可以实现多timer并行执行(没测试),但是还是那句话,ie不支持也是有其道理的,不要把web弄的太复杂了
...我一个菜鸟被楼上大哥称为大牛,烧的难受
fins
2007-11-12
晕 本来以为 hax把我教明白了 这一下又糊涂了
有没有官方的说法啊????
afcn0 hax jindw .... 等等各位js研究的大牛们
快出来给个正确答案啊
有没有官方的说法啊????
afcn0 hax jindw .... 等等各位js研究的大牛们
快出来给个正确答案啊
myy
2007-11-12
hax 写道
fins 写道
这些我理解了
但是 这个还是没明白 :(
但是 这个还是没明白 :(
是否是新开窗口,对于JS来说没有意义。
除非是两个完全没有任何关联的浏览器会话,理论上是可以在两个独立线程中的。
顺带说一下,JS本身一定是单线程的(除了特定的引擎扩展之外),这并不妨碍浏览器的其它部分是多线程的(问题是现有的浏览器实现,往往把脚本执行放在浏览器的主线程中)。但是其它任何一种异步机制或者外部多线程,如果牵涉到脚本,最终都会归并到JS的这一个线程中。所以XHR是异步的,CSS渲染是异步的,打开一个新窗口是异步的……都不能改变JS脚本的执行顺序。
据我所知,IE6 (IE7标签页方式不清楚) 用 open(), _balnk, Ctrl+N 等各种方式打开的新窗口都是在独立的线程中运行的,并且同时都属于一个IE进程,“浏览器的主线程”这种说法也不确切,事实上,同一个IE进程每个IE窗口线程都是平等的,根本没有哪个是“主线程”之说。也就是说,每个IE窗口线程中都有“全套”的东西,包括 js引擎。(不过,底层的网络通讯采用了线程池,这个是共享的)。
这样,虽然“JS本身一定是单线程的”,但是open()创建了两套“在不同线程中的js引擎环境”,通过这样来模拟 LZ 的要求是可行的。
fins
2007-11-12
非常感谢 :)
以前对这方面的了解确实太少了 现在知道了
谢谢
以前对这方面的了解确实太少了 现在知道了
谢谢
hax
2007-11-12
fins 写道
这些我理解了
但是 这个还是没明白 :(
但是 这个还是没明白 :(
是否是新开窗口,对于JS来说没有意义。
除非是两个完全没有任何关联的浏览器会话,理论上是可以在两个独立线程中的。
顺带说一下,JS本身一定是单线程的(除了特定的引擎扩展之外),这并不妨碍浏览器的其它部分是多线程的(问题是现有的浏览器实现,往往把脚本执行放在浏览器的主线程中)。但是其它任何一种异步机制或者外部多线程,如果牵涉到脚本,最终都会归并到JS的这一个线程中。所以XHR是异步的,CSS渲染是异步的,打开一个新窗口是异步的……都不能改变JS脚本的执行顺序。
hax
2007-11-12
fins 写道
to hax
我明白你的意思了
其实你是指, 理论上我说的对
但是实际情况中 我例子中的A方法会一直占有CPU ,使得方法B根本得不到运行的机会,对吧?
我明白你的意思了
其实你是指, 理论上我说的对
但是实际情况中 我例子中的A方法会一直占有CPU ,使得方法B根本得不到运行的机会,对吧?
我的意思是,由于JS是单线程执行的(除了某些带有扩展特性的引擎,如rhino),所以脚本其实没有可能进行真正意义上的多线程。
注意setTimeout/setInterval并非JS规范的一部分,而是浏览器提供的特性。而且它们本质上只是一个排程器,不可能中断尚未执行完成的脚本或者重入任何一个方法。否则必然会出现语义上的问题。真正多线程,必定要带有其它的原语,如锁定、同步、信号量——JS本身一样都没有。
我们可以用setTimeout来实现Executor和Queue,但是进入一个queue的任何一个任务一旦执行,就不可能被中断,只有它执行完成了,其他task才有机会执行。所以你必须手动把heavy的task分解成一系列小的task,才能模拟多线程。
未来的JS 2.0,我们仍然不会有多线程(除了引擎自己的扩展),但是我们有了yield,能以协程方式进行并行编程!
fins
2007-11-12
这些我理解了
但是 这个还是没明白 :(
这个我没明白
为什么新开个窗口后, 新窗口内执行的 js 和 原窗口是一个线程????
比如 原窗口内循环执行一个函数.
中途开了一个新窗口 新窗口内也是调用一个函数
难道那个窗口的函数要执行完了
原窗口的才会继续执行下去????
如果open的窗口 和原窗口是一个 script thread
那么 通过 <a href=... target='_blank' >....
打开的呢?? 也是???
但是 这个还是没明白 :(
引用
这个我没明白
为什么新开个窗口后, 新窗口内执行的 js 和 原窗口是一个线程????
比如 原窗口内循环执行一个函数.
中途开了一个新窗口 新窗口内也是调用一个函数
难道那个窗口的函数要执行完了
原窗口的才会继续执行下去????
如果open的窗口 和原窗口是一个 script thread
那么 通过 <a href=... target='_blank' >....
打开的呢?? 也是???
hax
2007-11-12
fins 写道
to Hax
下面一段代码,确实是先执行的B, 而不是A执行完之后再执行的B啊
下面一段代码,确实是先执行的B, 而不是A执行完之后再执行的B啊
当然是先B后A,因为根据timer的设定,B在A前。
我说的意思恰恰是,B总在A前,即使B是一个heavytask超过了A的timer所设定的时间,但是由于script引擎是单线程的,A总是要等到B执行完毕后才有机会执行。
hax
2007-11-12
fins 写道
hax 写道
myy 写道
可以考虑用 window.open() 开新窗口实现,这个在IE下肯定是多线程的
You r wrong. They always in one script thread.
这个我没明白
为什么新开个窗口后, 新窗口内执行的 js 和 原窗口是一个线程????
比如 原窗口内循环执行一个函数.
中途开了一个新窗口 新窗口内也是调用一个函数
难道那个窗口的函数要执行完了
原窗口的才会继续执行下去????
如果open的窗口 和原窗口是一个 script thread
那么 通过 <a href=... target='_blank' >....
打开的呢?? 也是???
你可以尝试一下你所构思的测试例子,看看结果如何。
halfmile
2007-11-10
JavaScript 虚拟机在一个浏览器中有多个实例吗?如果没有就无法实现多进程了。何况即便可以多进程,JavaScript也没有提供权限来取消进程,如果简单的抛弃进程,那么是否会造成内存泄漏呢?
一般耗时的function,大多是罗列或者递归操作。如果是两种操作的话,可以用一些技巧模拟可取消的进程。一个方法是把function里面的状态取出来放在外面,然后套一个很短的(1ms)interval来反复执行。当一定条件满足的时候,比如完成或者超时,那clearInterval就可以了。
一般耗时的function,大多是罗列或者递归操作。如果是两种操作的话,可以用一些技巧模拟可取消的进程。一个方法是把function里面的状态取出来放在外面,然后套一个很短的(1ms)interval来反复执行。当一定条件满足的时候,比如完成或者超时,那clearInterval就可以了。
fins
2007-11-10
to hax
我明白你的意思了
其实你是指, 理论上我说的对
但是实际情况中 我例子中的A方法会一直占有CPU ,使得方法B根本得不到运行的机会,对吧?
我明白你的意思了
其实你是指, 理论上我说的对
但是实际情况中 我例子中的A方法会一直占有CPU ,使得方法B根本得不到运行的机会,对吧?
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 581447 次
- 性别:

- 来自: 福建莆田@广州

- 详细资料
搜索本博客
我的相册
力拔千斤
共 146 张
共 146 张
最近加入圈子
链接
- 超越黎明
- CJSDN
- CSDN
- JavaWorld@TW
- JavaEye
- Spring中文论坛
- Matrix
- BEA dev2dev
- Agile Tao Forum
- Flickr
- developerWorks
- TheServerSide
- Sun Java Forum
- JavaRanch
- 满江红开源
- del.icio.us
- Sun中国技术社区
- 希赛网中国软考
- AJAX Design Patterns
- CSS: The Missing Manual
- Java Persistence with Hibernate
- Script in Java
- Building Spring 2 Enterprise Applications
- Tuscany中文社区
- 我爱人开的购物店,欢迎光临
最新评论
-
如何正确地在Axis、Axis2 ...
xly_971223 写道问一下用多少网站在真正的用web sevice?有多少 ...
-- by 咖啡舞者 -
如何在JavaScript中实现某 ...
afcn0 写道首先js是单线程的,lz的想法就不对,那是多线程,现在基本除了X ...
-- by andyhu1007 -
Script in Java中文版Java ...
司令很强大啊,呵呵
-- by fantasybei -
BEAer Last Day, Tomorrow ...
祝福司令, Bea亲密接触快一年了吧? 有什么感言呢? 和大家share一下吧 ...
-- by beckdim -
再叫我“小英雄”,我就揍 ...
有个小英雄好像被保送清华了
-- by beckdim






评论排行榜