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">  
  &nbsp;  
  </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   (希望先短信联系)。希望大家能给我问下,谁需要,谢谢   

加支付宝好友偷能量挖...


评论(0)网络
阅读(206)喜欢(1)JavaScript/Ajax开发技巧