JavaScript技巧:实现 sleep()
JavaScript是一个顺序解释性的语言,在网页里执行的时候往往想让它的执行暂停一下,但又没有对应的方法可用,于是就有人使用 N 万次的空循环来消耗时间,不过暂停是暂停了,但每台电脑对这个空循环的执行时间是不一样的,好的电脑可能只有零点几秒,但差的电脑就惨了,可能需要几秒甚至几十秒才能做完这些空操作,所以我特意修改了一下它的实现,可以达到定时量的暂停:
function sleep(n)
{
var start=new Date().getTime();
while(true) if(new Date().getTime()-start>n) break;
}
代码量不多,纯属于技巧卖弄而已,见笑了。
问题点数:50、回复次数:50
Top
1 楼qiushuiwuhen(秋水无恨)回复于 2006-03-03 22:50:16 得分 1笑纳了,不过好像有待优化
Top
2 楼astra1(Hyperion)回复于 2006-03-04 02:00:07 得分 1OTL 最有效实现
Top
3 楼pli0825(念叨念叨,我念叨死你!)回复于 2006-03-04 10:09:01 得分 1呵呵,代码虽简单,但是不容易想到。
学习了
Top
4 楼LCKKING(黑旋风)回复于 2006-03-04 10:16:01 得分 1非常有创意,不过这样还是解决不了根本根本问题.他这样循环又不能释放CPU,始终耗着
javascript不支持多线程永远是个痛....
Top
5 楼DeluxWorld(曾经的你)回复于 2006-03-04 10:20:27 得分 1想法不错~
Top
6 楼yiyioo(天一(一个人的Team))回复于 2006-03-04 10:26:42 得分 1用setInterval这个不行吗??
Top
7 楼dreadknightll(Dread Knight)回复于 2006-03-04 10:45:35 得分 1学习学习
Top
8 楼dh20156(风之石)回复于 2006-03-04 10:51:44 得分 1梅大想法很好。 ^_^
Top
9 楼yiyioo(天一(一个人的Team))回复于 2006-03-04 11:02:50 得分 1为什么
sleep(3);
后面加个
alert("ff");
这个延时就没有了;
还望大家帮忙解释一下,对这些东西俺不懂~~~
Top
10 楼treeroot(旗鲁特)回复于 2006-03-04 11:22:28 得分 1我觉得还是用
setTimeout模拟比较不错。
Top
11 楼dh20156(风之石)回复于 2006-03-04 11:23:09 得分 1sleep(3)时间太短了,看不到效果,你试试sleep(1000)。
Top
12 楼yiyioo(天一(一个人的Team))回复于 2006-03-04 11:40:48 得分 1原来是毫秒阿~~
可是这么写会先弹出s22再弹出s11,奇怪~
<script language="javascript">
var flag=""
function sleepI(n)
{
flag = window.setInterval("c()",1000*n);
}
function c(){alert("s11");window.clearInterval(flag);}
function test()
{
sleepI(3);
alert("s22");
}
</script>
<body>
<button onClick="test();" name="btn" value="BUTTON"></button>
</body>
不好意思,我是在简单问题复杂化~~~
Top
13 楼donghid(想得太多,快要疯掉了!神哪,让我静下来)回复于 2006-03-04 12:26:05 得分 1没什么奇怪的,setInterval执行时,其它的过程并不会等待的.
其实可以用setTimeout(函数,时间)来做延时,但是延时后要执行的代码则必须写在"函数"中了,破坏了程序的结构.
Top
14 楼hax(海曦)回复于 2006-03-04 14:05:11 得分 1梅老大同志,这次我要说你了,你这是玩哪出呢?
这个东西是忙等,根本起不到sleep的作用,反而容易把browser搞得crash。
更主要的是,除了把用户的cpu霸占之外,就没啥额外用途,例如你在之前setTimout 1秒的任务,然后忙等3秒,该任务结果还是要到3秒后即忙等完成才会执行的。。。
browser中的js几乎无法实现真正的sleep,至少我研究到现在没有什么解决方案。只有模态窗口(其实就跟alert一样),能做到非busy的等待,但也无法绕过js单线程的障碍。类似的方式还有在具有java的环境下,调用Thread.sleep,这个等待一点不耗cpu,然而因为无法使用wait,notify,所以还是白搭。
如果仅仅满足于非忙等,则上述方案都是可行的。除此之外还有一个技巧,一定程度上可能可以使用非忙等并且同步方式,待我全面验证之后再行发表。
Top
15 楼hax(海曦)回复于 2006-03-04 15:29:11 得分 1唉,刚才测试了一下,惊讶的发现ie和ff的表现正好完全相反。。。
ie在alert的时候,setTimeout的代码是不会执行的,但是XMLHttpRequest的onreadystatechange是会执行的。ff正好相反,setTimeout的代码是会执行的,而onreadystatechange却不执行。。。
郁闷。。。
Top
16 楼fason(咖啡人生)回复于 2006-03-04 17:33:23 得分 1以前是专门写过一个模拟单线程操作的东西...
Top
17 楼hax(海曦)回复于 2006-03-04 20:11:29 得分 1to fason:
什么叫模拟单线程?你是不是模拟多线程啊?
Top
18 楼zhaoxiaoyang(梅雪香@深圳)回复于 2006-03-04 21:05:16 得分 1fason是不是说这个..
<html>
<head>
<title>emu -- 用command模式模拟多线程</title>
</head>
<body>
<SCRIPT LANGUAGE="JavaScript">
<!--
var commandList = [];
function executeCommands(){
if (commandList.length>0){
commandList.shift()();
}
}
function startNewTask(){
var resultTemp = document.createElement("span");
document.body.insertBefore(resultTemp,document.body.lastChild);
document.body.insertBefore(document.createElement("br"),document.body.lastChild);
resultTemp.innerText = 0;
commandList.push(function(){simThread(resultTemp,0);});
}
function simThread(temp,n){
temp.innerText = temp.innerText-(-n);
if (n<1000)
commandList.push(function(){simThread(temp,++n);});
else{
document.body.removeChild(temp.nextSibling);
document.body.removeChild(temp);
}
}
window.onload = function(){setInterval("executeCommands()",1);}
//-->
</SCRIPT>
<button onclick="startNewTask()">start</button>
<BR><BR>
</body>
</html>
Top
19 楼hax(海曦)回复于 2006-03-04 21:31:43 得分 1哦,用队列模拟多线程哦。
Top
20 楼mingxuan3000(铭轩)回复于 2006-03-04 22:00:41 得分 1xmark
Top
21 楼liu76xt((网事随逢))回复于 2006-03-05 11:01:14 得分 1挺好的~
Top
22 楼meizz(梅花雪)回复于 2006-03-06 10:54:35 得分 0 在浏览器里没有系统sleep的功能,只能自己模拟,当然在IE里用模态框是一个不错的解决方案,至少可以不占用CPU资源,不过模态框没有兼容性呀。这种空循环的sleep()在一般的情况下我也不推荐使用,但在极个别的地方,用用也无妨呀。
Top
23 楼gu1dai(异域苍穹.百年飞行)回复于 2006-03-06 11:12:28 得分 1settimeout不好吗?模态框?没听过。
Top
24 楼hax(海曦)回复于 2006-03-06 12:33:30 得分 2梅大同志,忙等循环占着cpu,在差一点的机器上,就可能造成机器死机、ie崩溃之类的。而且在忙等一段时间后,ie和ff都会询问用户是否停止脚本。所以我觉得不能使用它啊!
一定要模拟的话,ie下用modal窗口,ff下其实也有modal窗口(window.open加参数),问题是需要一个非默认的权限,所以我能想到的只有调用java下的Thread.sleep,但是这样没有安装java就不行了。实际上,ff的settimeout貌似是不错的,问题是我没有想出一个好的阻塞方法。
最后,还有一招,就是用xmlhttprequest的同步调用,去访问一个网页,该动态网页等若干时间再返回。此动态网页可以用servlet等来写。示例如下:
package net.sf.pies.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class for Servlet: HttpStreamServlet
*
*/
public class HttpStreamServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
/**
*
*/
private static final long serialVersionUID = 1L;
/* (non-Java-doc)
* @see javax.servlet.http.HttpServlet#HttpServlet()
*/
public HttpStreamServlet() {
super();
}
/* (non-Java-doc)
* @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
int time = Integer.parseInt(request.getParameter("time"));
try {
Thread.sleep(time);
out.println(time);
} catch (InterruptedException e) {
throw new ServletException(e);
}
}
/* (non-Java-doc)
* @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
以上,如果以 sleep?time=2000 调用(假设该servlet被mapping到/sleep上),则会等待2秒后输出2000。
这个方法适用于所有具有同步调用的环境,不过缺点是,时间不太准确,因为要访问server,虽然可以进一步引入时间同步代码,但总不适于要求等待时间较短的情况。唉,如果xmlhttprequest能设timeout就好了。
Top
25 楼meizz(梅花雪)回复于 2006-03-06 15:00:26 得分 0 嗯,你的 xmlhttp 同步法不失为一种非常好的解决方案,我这个 sleep 适合在那个要极短暂停(建议不要超过1000毫秒),且不太适合使用 setTimeout 之类延迟的情况。
Top
26 楼hansonboy(hansonboy)回复于 2006-03-06 16:02:02 得分 1<script>
function sleep(n)
{
var start=new Date().getTime();
while(true) if(new Date().getTime()-start>n) break;
}
for(var i = 1;i<11;i++){
document.write("第" + i + "行<br>");
sleep(1000);
}
</script>
用你的方法测试了一下, 结果要等待10秒全才全部一次输出来
Top
27 楼hax(海曦)回复于 2006-03-06 17:46:08 得分 1to 楼上,这是因为忙等的原因。
在你这个例子里,最好使用setTimeout或setInterval。
Top
28 楼JK_10000(JK)回复于 2006-03-06 18:10:07 得分 1应该可以实现不耗cpu的真正挂起吧.
等会我去试试
Top
29 楼JK_10000(JK)回复于 2006-03-06 18:43:47 得分 1果然可以实现
代码如下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JK:支持民族工业,尽量少买X货</title>
<script language=javascript>
function sleep(num) //JK
{
var tempDate=new Date();
var theXmlHttp = new ActiveXObject( "Microsoft.XMLHTTP" );
while((new Date()-tempDate)<num )
{
try{
theXmlHttp .open( "get", "http://www.google.com/JK.asp?JK="+Math.random(), false );
theXmlHttp .send();
}
catch(e){;}
}
return;
}
</script>
</head>
<body>
js不耗(耗得比较少)cpu的
sleep(ms):<input value=10000 name=aaa > ,<input type=button value="alert(0);sleep(..);alert(1);" onclick="alert(0);sleep(document.all.aaa.value);alert(1);">
</body>
</html>
Top
30 楼yiyioo(天一(一个人的Team))回复于 2006-03-07 09:14:02 得分 1这个帖子的含金量越来越高了~`
继续UP
Top
31 楼JK_10000(JK)回复于 2006-03-07 10:23:28 得分 2把url改成about:blank,可以提高sleep的毫秒的精度。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JK:支持民族工业,尽量少买X货</title>
<script language=javascript>
function sleep(num) //JK
{
var tempDate=new Date();
var tempStr="";
var theXmlHttp = new ActiveXObject( "Microsoft.XMLHTTP" );
while((new Date()-tempDate)<num )
{
tempStr+="\n"+(new Date()-tempDate);
try{
theXmlHttp .open( "get", "about:blank?JK="+Math.random(), false );
theXmlHttp .send();
}
catch(e){;}
}
containerDiv.innerText=tempStr;
return;
}
</script>
</head>
<body>
js不耗(耗得比较少)cpu的
sleep(ms):<input value=10000 name=aaa > ,<input type=button value="alert(0);sleep(..);alert(1);" onclick="alert(0);sleep(document.all.aaa.value);alert(1);">
<div id=containerDiv>
</div>
</body>
</html>
Top
32 楼yjbnew(伟大的光荣的正确的ASP千岁千岁千千岁)回复于 2006-03-07 10:33:26 得分 1while((new Date()-tempDate)<num )
这条很耗cpu的!
Top
33 楼ice_berg16(寻梦的稻草人)回复于 2006-03-07 10:42:04 得分 1目前还没发现用到这个功能的地方,
定时执行都可以用setTimeout来解决
Top
34 楼JK_10000(JK)回复于 2006-03-07 10:42:48 得分 1to: yjbnew
虽说比较耗cpu,但不至于多得成为耗cpu的主要原因
tempStr只是为了演示url与cpu耗用以及时间精度的关系
改一下url可以看到不同的cup耗用和不同的时间精度
如果把url定成google,好像有点对不起google。
如果把url定成一个不存在的url,精度就相当于变成request的timeout时间
如果把url定成about:blank,那这样只是耗掉自己的cup
。。。
Top
35 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-03-07 10:43:18 得分 1为什么不通过setTimeout函数啊?
既然传对象参数可以重载setTimeout函数,为什么不重载这个函数的第二个参数
把第二个参数调大,已达到sleep的目的。
Top
36 楼JK_10000(JK)回复于 2006-03-07 10:50:30 得分 1本来是希望XMLHTTPRequest有一个setRequestTimeout(ms)的方法,
可惜的是没有。
另,to:hbhbhbhbhb1021(天外水火(我要多努力))
window.setTimeout方法是立即返回,
sleep应该是希望过一段时间再返回吧.
我也不觉得sleep有什么用处
编码这么多年,还没碰到过要用的情况呢
Top
37 楼meizz(梅花雪)回复于 2006-03-07 10:54:36 得分 0 嗯,setTimeout 并没有达到sleep的功能,并没有阻止主程序的运行。sleep在某些特殊的场合下还是有些用处的,即然 xmlhttp 法是最优化的,那我再花点时间把这个功能代码优化一下再发布。
Top
38 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-03-07 10:55:27 得分 1整理了下思路,上面可能没表述清楚,
可以多传一个参数,然后判断第三个参数,如果满足一定的要求就把第二个参数调大。不满足则不变
Top
39 楼hax(海曦)回复于 2006-03-07 13:37:34 得分 1梅老大加油优化吧。
建议在ff上首先检测是否存在java,如果可以的话优先使用 Thread.sleep 。
Top
40 楼sinofool(蠢材的我)回复于 2006-03-07 14:01:19 得分 1如果不是只运行一次两次,而是连续的间隔运行,用递归的setTimedout可以实现。
但是IE浏览器好像不会释放递归里面变量的内存。
只要一两次运行的话,既然javascript没有多线程的设计,就用浏览器自己的刷新机制来运行吧。
Top
41 楼ttyp(@http://www.cnblogs.com/ttyp/)回复于 2006-03-07 18:42:18 得分 1js本身是没办法办到的,借助其他也许可能做成真正的sleep
ServerXMLHTTP有个setTimeouts方法
var xmlServerHttp = new ActiveXObject("Msxml2.ServerXMLHTTP.4.0");
var lResolve = 5 * 1000;
var lConnect = 5 * 1000;
var lSend = 15 * 1000;
var lReceive = 15 * 1000;
xmlServerHttp.setTimeouts(lResolve, lConnect, lSend, lReceive);
xmlServerHttp.open("GET", "http://localhost/sample.xml", false);
xmlServerHttp.send();
Top
42 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-03-08 10:03:56 得分 1to JK
setTimeout是立即返回,是不能完全实现sleep那种,只是模拟,有点象。执行的时候不是有个延迟吗?动态的把延迟加大,也就是说每次执行的延迟时间不同。这样如果是在循环执行过程中的,就可以达到sleep的这个效果,比如
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>WaterFire</title>
</head>
<script language=javascript>
num=1;
var _st = window.setTimeout;
window.setTimeout = function(fRef,mDelay)
{
if (typeof fRef=="function")
{
if(arguments.length>2)
{
mDelay=parseInt(arguments[2])*parseInt(1000)+parseInt(mDelay);
return _st(fRef,mDelay)
}
}
return _st(fRef,mDelay);
}
function writeNum()
{
if(num==5)//执行第5次的时候调用sleep方法,延迟5秒执行
{
document.getElementById("div1").innerText=num+"这次延迟";
sleep(5);
}
else
{
document.getElementById("div1").innerText=num;
num=parseInt(num)+parseInt(1);
window.setTimeout("writeNum()",1000);
}
}
function sleep(timeNum)
{
window.setTimeout(writeNum,1000,timeNum);
num=num+parseInt(1);
}
</script>
<body onload=writeNum()>
<div id="div1">
</div>
</body>
</html>
Top
43 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-03-08 10:23:45 得分 1function sleep(timeNum)
{
window.setTimeout(writeNum,1000,timeNum);
num=num+parseInt(1);//这句没用,去掉!
}
</script>
TO meizz
我这样做是没有阻止主线程
期待xmlHttp的新版本
Top
44 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-03-08 10:34:49 得分 2ttyp的方法刚查了下
oServerXMLHTTPRequest.setTimeouts(resolveTimeout, connectTimeout,
sendTimeout, receiveTimeout);
Parameters
resolveTimeout
A long integer. The value is applied to mapping host names (such as "www.microsoft.com") to IP addresses; the default value is infinite, meaning no timeout.
connectTimeout
A long integer. The value is applied to establishing a communication socket with the target server, with a default timeout value of 60 seconds.
sendTimeout
A long integer. The value applies to sending an individual packet of request data (if any) on the communication socket to the target server. A large request sent to a server will normally be broken up into multiple packets; the send timeout applies to sending each packet individually. The default value is 30 seconds.
receiveTimeout
A long integer. The value applies to receiving a packet of response data from the target server. Large responses will be broken up into multiple packets; the receive timeout applies to fetching each packet of data off the socket. The default value is 30 seconds.
Top
45 楼laochake(老茶客)回复于 2006-03-08 12:13:32 得分 1等我先泡杯茶。。。
Top
46 楼loveme4180(孤独剑)回复于 2006-04-26 13:08:47 得分 1好精彩,顶
Top
47 楼zmm049(密码12345678)回复于 2006-05-15 11:36:01 得分 1怎么没有下文了?
Top
48 楼iasky(iasky)回复于 2006-05-15 11:39:06 得分 1MARK
Top
49 楼luoyefudi()回复于 2006-05-15 12:33:26 得分 1买重了《javascript权威指南》,出售一本,特价!这本书,想必玩过javascrip的都略有耳闻的,很好的一本书,但我买了一本,我的一个朋友同时又给我买了,郁闷!现特价出售其中一本,原价是99元的,我现在只卖70!不说什么合算不合算了,希望与你交个朋友!反正大家都是搞程序的,如果能与你相识,相信也是缘分,对了,我在上海,最好能是在上海的朋友买到这本书,都比较方便,亲手交书,也好,免得大家不相信。可以联系我电话,13585892686 (希望先短信联系)。希望大家能给我问下,谁需要,谢谢
加支付宝好友偷能量挖...