zoukankan      html  css  js  c++  java
  • 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中绝大数执行正常;

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

    为什么正常?这是因为计时器在所有的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>
    
    

    此时浏览器显示结果为

    或者为

    本文首发:http://www.cnblogs.com/sprying/archive/2013/05/29/3105268.html
    参考:http://www.cnblogs.com/diguonianzhu/archive/2012/06/29/2570371.html
    有任何问题,欢迎留言交流。 注意:已解决的问题,会在整理后删除掉。

    *******站在巨人的肩膀上

  • 相关阅读:
    DRF-serializers.Serializer序列化器
    docker 打包容器和导入
    python 打包exex文件
    python 判断ip是否正确 re学习
    快排
    冒泡排序
    二分法查找
    递归实现斐波那契
    排序算法
    迭代器构造斐波那契数列
  • 原文地址:https://www.cnblogs.com/sprying/p/3105268.html
Copyright © 2011-2022 走看看