JavaScript的setTimeout与setInterval执行时机

继前篇 谈谈JavaScrip的异步实现 ,我们知道JavaScript引擎是单线程的,所有的js的代码都将在这个单线程中执行。像浏览器事件、计时器等异步只是个幌子,异步时js并没有多个线程在执行,而是都排列在一个待执行队伍中。

setTimeout的使用方法

setTimeout(function(){},time)--可以正确执行。

setTimeout("js语句",time)--可以正确执行。 js语句可以是多条语句。

setTimeout(fun,time)

只引用函数名字,也可运行,但是要注意的是:如果fun是某个对象的方法,则fun函数内的this此时被当做window。

eg:

var obj =

{

    "p1": "obj的属性p1",

    "fun": function () {

        alert(this.p1);

    }

};



setTimeout(obj.fun, 1000);

运行后的结果,是undefined。用函数式对象定义对象也是此种结果。用方法1则可以输出正确的结果。

setTimeout(fun(),time)--不正确使用

不能正确执行,因为fun()会立即执行,没有延迟time时间后执行。

执行时机

当页面初始化时,setTimeout与setInterval的回调与队列中其它回调执行次序是怎样的?《JavaScript权威指南》中介绍的,setTimeout的回调发生在所有的事件都处理完,这句到底是不是对的?带着这些疑问,我们先来看个例子:

 1 <!DOCTYPE html>

 2 <html>

 3 <head>

 4     <title></title>

 5     <meta http-equiv="content-type" content="text/html;charset=utf-8">

 6     <script type="text/javascript" src="a.js"></script>

 7     <script type="text/javascript">

 8         var  before_x = 2;

 9     </script>

10     <script type="text/javascript">

11         var middle_x =3;

12         // 页面head中js执行完毕后,执行队列(页面尾部的js,定时器回调、事件回调,究竟哪个先执行,这个随机的);

13         setTimeout(function(){

14             console.log("Timeout:"+(ax+before_x+middle_x+middle_y+bx+cx+domLoad_x+inner_x));

15         },0);

16         var inter = setInterval(function(){

17             console.log("Interval:"+(ax+before_x+middle_x+middle_y+bx+inner_x+domLoad_x+cx));

18             clearInterval(inter);

19         },1)

20         var middle_y =1;

21     </script>

22     <script type="text/javascript" src="b.js"></script>

23 </head>

24 <body>

25      <input type="text" id="inp_click" onclick="inner_x =1;for(var i=0;i<1000000;i++){inner_x++};console.log('clickEvent:'+inner_x);">

26 </body>

27 </html>

28 <script type="text/javascript" src="c.js"></script>

29         <script type="text/javascript">

30             var start_time = new Date().getTime();

31             for(var i= 1;i<1000000;i++){

32 

33             }

34             var end_time = new Date().getTime();

35             console.log('after the html,wait:'+(end_time-start_time));

36             var inp = document.getElementById("inp_click");

37             var event = document.createEvent("MouseEvent");

38             event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);

39             inp.dispatchEvent(event);

40             var domLoad_x = 4;

41         </script>

  a.js

1  var ax =1;

  b.js

1  var bx = 2;

  c.js

1 var cx =3;

 

chrome中绝大数执行正常;

JavaScript的setTimeout与setInterval执行时机

偶尔会报错,特别是在页面刚在浏览器中打开时,出现以下错误

JavaScript的setTimeout与setInterval执行时机

为什么正常?这是因为计时器在所有的js都执行完后才执行,包括页面尾部的js,模拟触发的事件回调。

为什么报错?这是因为计时器在页面尾部js执行前,先执行。

结论:页面head中js执行完毕后,执行队列(页面尾部的js,定时器回调、事件回调),究竟哪个先执行,这个随机的。

《JavaScript高级程序设计》介绍到DomContentLoaded事件时,提到了
setTimeout(function(){
  //此处添加事件处理程序代码
},0);
用以弥补老式浏览器不支持DomContentLoaded。

如果你们还有兴趣,我们再来看个例子,至于为什么是这样,大家自己去思考。
  1 <!DOCTYPE html>

  2 <html>

  3 <head>

  4     <title></title>

  5     <meta http-equiv="content-type" content="text/html;charset=utf-8">

  6     <script type="text/javascript" src="a.js"></script>

  7     <script type="text/javascript">

  8         var  before_x = 2;

  9         (function(window, undefined) {

 10             var readyList = [],

 11                     isReady = 0,

 12                     readyBound = false,

 13                     init,

 14                     bindReady,

 15                     readyWait = 1;

 16             init = function(wait) { // A third-party is pushing the ready event forwards

 17                 if (wait === true) {

 18                     readyWait--;

 19                 } // Make sure that the DOM is not already loaded

 20                 if (!readyWait || (wait !== true && !isReady)) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).

 21                     // 确保body元素存在,这个操作是防止IE的bug

 22                     if (!document.body) {

 23                         return setTimeout(init, 1);

 24                     } // dom渲染完成标志设置为true

 25                     isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be

 26                     if (wait !== true && --readyWait > 0) {

 27                         return;

 28                     } // 绑定的渲染完成后的执行函数

 29                     if (readyList) { // 全部执行

 30                         var fn, i = 0,

 31                                 ready = readyList; // 重置

 32                         readyList = null;

 33                         while ((fn = ready[i++])) {

 34                             fn.call(document);

 35                         }

 36                     }

 37                 }

 38             }; // 初始化readyList事件处理函数队列

 39             // 兼容不同浏览对绑定事件的区别

 40             bindReady = function() {

 41                 if (readyBound) {

 42                     return;

 43                 }

 44                 readyBound = true; // $(document).ready()的嵌套调用时

 45                 // readyState: "uninitalized"、"loading"、"interactive"、"complete" 、"loaded"

 46                 if (document.readyState === "complete") { // 让它异步执行,使这个ready能延迟

 47                     return setTimeout(init, 1);

 48                 } // Mozilla, Opera and webkit

 49                 // 兼容事件,通过检测浏览器的功能特性,而非嗅探浏览器

 50                 if (document.addEventListener) { // 使用事件回调函数

 51                     document.addEventListener("DOMContentLoaded",

 52                             function() {

 53                                 document.removeEventListener("DOMContentLoaded", arguments.callee, false);

 54                                 init();

 55                             },

 56                             false); // 绑定回调到load,使之能一定执行

 57                     window.addEventListener("load", init, false); // IE

 58                 } else if (document.attachEvent) { // 确保在load之前触发onreadystatechange,

 59                     // 针对iframe情况,可能有延迟

 60                     document.attachEvent("onreadystatechange",

 61                             function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).

 62                                 if (document.readyState === "complete") {

 63                                     document.detachEvent("onreadystatechange", arguments.callee);

 64                                     init();

 65                                 }

 66                             }); // 绑定回调到一定执行能load事件

 67                     window.attachEvent("onload", init); // 如果是IE且非iframe情况下

 68                     // 持续的检查,看看文档是否已准备

 69                     var toplevel = false;

 70                     try {

 71                         toplevel = window.frameElement == null;

 72                     } catch(e) {}

 73                     (function() {

 74                         if (document.documentElement.doScroll && toplevel) {

 75                             if (isReady) {

 76                                 return;

 77                             }

 78                             try { // If IE is used, use the trick by Diego Perini

 79                                 // http://javascript.nwbox.com/IEContentLoaded/

 80                                 document.documentElement.doScroll("left");

 81                             } catch(e) {

 82                                 setTimeout(arguments.callee, 1);

 83                                 return;

 84                             } // 执行在等待的函数

 85                             init();

 86                         }

 87                     })();

 88                 }

 89             };

 90             window.ready = function(fn) { // 绑定上监听事件

 91                 bindReady(); // 如果dom已经渲染

 92                 if (isReady) { // 立即执行

 93                     fn.call(document); // 否则,保存到缓冲队列,等上面的监听事件触发时,再全部执行

 94                 } else if (readyList) { // 将回调增加到队列中

 95                     readyList.push(fn);

 96                 }

 97             };

 98         })(window);

 99     </script>

100     <script type="text/javascript">

101         var middle_x =3;

102         // 页面head中js执行完毕后,执行队列(页面尾部的js,定时器回调、事件回调,究竟哪个先执行,这个随机的);

103         setTimeout(function(){

104             console.log("Timeout:"+(ax+before_x+middle_x+middle_y+bx+cx+domLoad_x+inner_x));

105         },0);

106         var inter = setInterval(function(){

107             console.log("Interval:"+(ax+before_x+middle_x+middle_y+bx+inner_x+domLoad_x+cx));

108             clearInterval(inter);

109         },5000)

110         var middle_y =1;

111         window.onload = function(event){

112              console.log("onloaded");

113         }

114         ready(function(event){

115             console.log("dom loaded");

116         });

117     </script>

118     <script type="text/javascript" src="b.js"></script>

119 </head>

120 <body>

121      <input type="text" id="inp_click" onclick="inner_x =1;for(var i=0;i<1000000;i++){inner_x++};console.log('clickEvent:'+inner_x);">

122 </body>

123 </html>

124 <script type="text/javascript" src="c.js"></script>

125         <script type="text/javascript">

126             var start_time = new Date().getTime();

127             for(var i= 1;i<1000000;i++){

128 

129             }

130             var end_time = new Date().getTime();

131             console.log('after the html,wait:'+(end_time-start_time));

132             var inp = document.getElementById("inp_click");

133             var event = document.createEvent("MouseEvent");

134             event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);

135             inp.dispatchEvent(event);

136             var domLoad_x = 4;

137         </script>
 
  

此时浏览器显示结果为

JavaScript的setTimeout与setInterval执行时机

或者为

JavaScript的setTimeout与setInterval执行时机

本文首发:http://www.cnblogs.com/sprying/archive/2013/05/29/3105268.html
参考:http://www.cnblogs.com/diguonianzhu/archive/2012/06/29/2570371.html

 

你可能感兴趣的:(SetInterval)