<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入理解定時器系列第一篇——理解setTimeout和setInterval

      前面的話

        很長時間以來,定時器一直是javascript動畫的核心技術。但是,關于定時器,人們通常只了解如何使用setTimeout()和setInterval(),對它們的內在運行機制并不理解,對于與預想不同的實際運行狀況也無法解決。本文將詳細介紹定時器的相關內容

       

      setTimeout()

        setTimeout()方法用來指定某個函數或字符串在指定的毫秒數之后執行。它返回一個整數,表示定時器的編號,這個值可以傳遞給clearTimeout()用于取消這個函數的執行

        以下代碼中,控制臺先輸出0,大概過1000ms即1s后,輸出定時器setTimeout()方法的返回值1

      var Timer = setTimeout(function(){
          console.log(Timer);
      },1000);
      console.log(0);

        也可以寫成字符串參數的形式,由于這種形式會造成javascript引擎兩次解析,降低性能,故不建議使用

      var Timer = setTimeout('console.log(Timer);',1000);
      console.log(0);

        如果省略setTimeout的第二個參數,則該參數默認為0

        以下代碼中,控制臺出現0和1,但是0卻在前面,后面會解釋這個疑問

      var Timer = setTimeout(function(){
          console.log(Timer);
      });
      console.log(0);

        實際上,除了前兩個參數,setTimeout()方法還允許添加更多的參數,它們將被傳入定時器中的函數中

        以下代碼中,控制臺大概過1000ms即1s后,輸出2,而IE9-瀏覽器只允許setTimeout有兩個參數,不支持更多的參數,會在控制臺輸出NaN

      setTimeout(function(a,b){
        console.log(a+b);
      },1000,1,1);

        可以使用IIFE傳參來兼容IE9-瀏覽器的函數傳參

      setTimeout((function(a,b){
          return function(){
              console.log(a+b);
          }
      })(1,1),1000);

        或者將函數寫在定時器外面,然后函數在定時器中的匿名函數中帶參數調用

      function test(a,b){
          console.log(a+b);
      }
      setTimeout(function(){
          test(1,1);
      },1000);

        [注意]IE8-瀏覽器不允許向定時器中傳遞事件對象event,如果要使用事件對象中的某些屬性,可以將其保存在變量中傳遞進去

      div.onclick = function(e){
          e = e || event;
          var type = e.type;
          setTimeout(function(){
              console.log(type);//click
              console.log(e.type);//報錯
          })
      }

      this指向

        在this機制系列已經詳細介紹過this指向的4種綁定規則,由于定時器中的this存在隱式丟失的情況,且極易出錯,因此在這里再次進行說明

      var a = 0;
      function foo(){
          console.log(this.a);
      };
      var obj = {
          a : 2,
          foo:foo
      }
      setTimeout(obj.foo,100);//0
      //等價于
      var a = 0;
      setTimeout(function foo(){
          console.log(this.a);
      },100);//0

        若想獲得obj對象中的a屬性值,可以將obj.foo函數放置在定時器中的匿名函數中進行隱式綁定

      var a = 0;
      function foo(){
          console.log(this.a);
      };
      var obj = {
          a : 2,
          foo:foo
      }
      setTimeout(function(){
          obj.foo();
      },100);//2

        或者也可以使用bind方法將foo()方法的this綁定到obj上

      var a = 0;
      function foo(){
          console.log(this.a);
      };
      var obj = {
          a : 2,
          foo:foo
      }
      setTimeout(obj.foo.bind(obj),100);//2

      clearTimeout()

        setTimeout函數返回一個表示計數器編號的整數值,將該整數傳入clearTimeout函數,取消對應的定時器

      //過100ms后,控制臺輸出setTimeout()方法的返回值1
      var Timer = setTimeout(function(){
          console.log(Timer);
      },100);

        于是可以利用這個值來取消對應的定時器

      var Timer = setTimeout(function(){
          console.log(Timer);
      },100);
      clearTimeout(Timer);

        或者直接使用返回值作為參數

      var Timer = setTimeout(function(){
          console.log(Timer);
      },100);
      clearTimeout(1);

        一般來說,setTimeout返回的整數值是連續的,也就是說,第二個setTimeout方法返回的整數值比第一個的整數值大1

      //控制臺輸出1、2、3
      var Timer1 = setTimeout(function(){
          console.log(Timer1);
      },100);
      var Timer2 = setTimeout(function(){
          console.log(Timer2);
      },100);
      var Timer3 = setTimeout(function(){
          console.log(Timer3);
      },100);

       

      setInterval()

        setInterval的用法與setTimeout完全一致,區別僅僅在于setInterval指定某個任務每隔一段時間就執行一次,也就是無限次的定時執行

      <button id="btn">0</button>
      <script>
      var timer = setInterval(function(){
          btn.innerHTML = Number(btn.innerHTML) + 1;
      },1000);
      btn.onclick = function(){
          clearInterval(timer);
          btn.innerHTML = 0;
      }
      </script>

        [注意]HTML5標準規定,setTimeout的最短時間間隔是4毫秒;setInterval的最短間隔時間是10毫秒,也就是說,小于10毫秒的時間間隔會被調整到10毫秒

        大多數電腦顯示器的刷新頻率是60HZ,大概相當于每秒鐘重繪60次。因此,最平滑的動畫效的最佳循環間隔是1000ms/60,約等于16.6ms

        為了節電,對于那些不處于當前窗口的頁面,瀏覽器會將時間間隔擴大到1000毫秒。另外,如果筆記本電腦處于電池供電狀態,Chrome和IE10+瀏覽器,會將時間間隔切換到系統定時器,大約是16.6毫秒

       

      運行機制

        下面來解釋前面部分遺留的疑問,為什么下面代碼的控制臺結果中,0出現在1的前面呢?

      setTimeout(function(){
          console.log(1);
      });
      console.log(0);

        實際上,把setTimeout的第二個參數設置為0s,并不是立即執行函數的意思,只是把函數放入異步隊列。瀏覽器先執行完同步隊列里的任務,才會去執行異步隊列中的任務

        在下面這個例子中,給一個按鈕btn設置了一個事件處理程序。事件處理程序設置了一個250ms后調用的定時器。點擊該按鈕后,首先將onclick事件處理程序加入隊列。該程序執行后才設置定時器,再有250ms后,指定的代碼才被添加到隊列中等待執行

      btn.onclick = function(){
          setTimeout(function(){
              console.log(1);
          },250);
      }

        如果上面代碼中的onclick事件處理程序執行了300ms,那么定時器的代碼至少要在定時器設置之后的300ms后才會被執行。隊列中所有的代碼都要等到javascript進程空閑之后才能執行,而不管它們是如何添加到隊列中的

        如圖所示,盡管在255ms處添加了定時器代碼,但這時候還不能執行,因為onclick事件處理程序仍在運行。定時器代碼最早能執行的時機是在300ms處,即onclick事件處理程序結束之后

      setInterval()的問題

        使用setInterval()的問題在于,定時器代碼可能在代碼再次被添加到隊列之前還沒有完成執行,結果導致定時器代碼連續運行好幾次,而之間沒有任何停頓。而javascript引擎對這個問題的解決是:當使用setInterval()時,僅當沒有該定時器的任何其他代碼實例時,才將定時器代碼添加到隊列中。這確保了定時器代碼加入到隊列中的最小時間間隔為指定間隔

        但是,這樣會導致兩個問題:1、某些間隔被跳過;2、多個定時器的代碼執行之間的間隔可能比預期的小

        假設,某個onclick事件處理程序使用setInterval()設置了200ms間隔的定時器。如果事件處理程序花了300ms多一點時間完成,同時定時器代碼也花了差不多的時間,就會同時出現跳過某間隔的情況

        例子中的第一個定時器是在205ms處添加到隊列中的,但是直到過了300ms處才能執行。當執行這個定時器代碼時,在405ms處又給隊列添加了另一個副本。在下一個間隔,即605ms處,第一個定時器代碼仍在運行,同時在隊列中已經有了一個定時器代碼的實例。結果是,在這個時間點上的定時器代碼不會被添加到隊列中

      迭代setTimeout

        為了避免setInterval()定時器的問題,可以使用鏈式setTimeout()調用

      setTimeout(function fn(){
          setTimeout(fn,interval);
      },interval);

        這個模式鏈式調用了setTimeout(),每次函數執行的時候都會創建一個新的定時器。第二個setTimeout()調用當前執行的函數,并為其設置另外一個定時器。這樣做的好處是,在前一個定時器代碼執行完之前,不會向隊列插入新的定時器代碼,確保不會有任何缺失的間隔。而且,它可以保證在下一次定時器代碼執行之前,至少要等待指定的間隔,避免了連續的運行

        使用setInterval()

      <div id="myDiv" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div>
      <script>
      myDiv.onclick = function(){
          var timer = setInterval(function(){
              if(parseInt(myDiv.style.left) > 200){
                  clearInterval(timer);
                  return false;
              }
              myDiv.style.left = parseInt(myDiv.style.left) + 5 + 'px';    
      
          },16);    
      }
      </script>

         使用鏈式setTimeout()

      <div id="myDiv" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div>
      <script>
      myDiv.onclick = function(){
          setTimeout(function fn(){
              if(parseInt(myDiv.style.left) <= 200){
                  setTimeout(fn,16);    
              }else{
                  return false;
              }
              myDiv.style.left = parseInt(myDiv.style.left) + 5 + 'px';    
          },16);    
      }
      </script>

       

      應用

        使用定時器來調整事件發生順序

        【1】網頁開發中,某個事件先發生在子元素,然后冒泡到父元素,即子元素的事件回調函數,會早于父元素的事件回調函數觸發。如果,我們先讓父元素的事件回調函數先發生,就要用到setTimeout(f, 0)

        正常情況下,點擊div元素,先彈出0,再彈出1

      <div id="myDiv" style="height: 100px;width: 100px;background-color: pink;"></div>
      <script>
      myDiv.onclick = function(){
          alert(0);
      }
      document.onclick = function(){
          alert(1);
      }
      </script>

        如果進行想讓document的onclick事件先發生,即點擊div元素,先彈出1,再彈出0。則進行如下設置

      <div id="myDiv" style="height: 100px;width: 100px;background-color: pink;"></div>
      <script>
      myDiv.onclick = function(){
          setTimeout(function(){
              alert(0);
          })
      }
      document.onclick = function(){
          alert(1);
      }
      </script>

        【2】用戶自定義的回調函數,通常在瀏覽器的默認動作之前觸發。比如,用戶在輸入框輸入文本,keypress事件會在瀏覽器接收文本之前觸發。因此,下面的回調函數是達不到目的

      <input type="text" id="myInput">
      <script>
      myInput.onkeypress = function(event) {
        this.value = this.value.toUpperCase();
      }
      </script>

        上面代碼想在用戶輸入文本后,立即將字符轉為大寫。但是實際上,它只能將上一個字符轉為大寫,因為瀏覽器此時還沒接收到文本,所以this.value取不到最新輸入的那個字符

        只有用setTimeout改寫,上面的代碼才能發揮作用

      <input type="text" id="myInput">
      <script>
      myInput.onkeypress = function(event) {
          setTimeout(function(){
              myInput.value = myInput.value.toUpperCase();
          });
      }
      </script>

      posted @ 2016-08-15 22:04  小火柴的藍色理想  閱讀(64316)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 深夜福利成人免费在线观看| 熟女一区| 国产男人的天堂在线视频| 18禁亚洲一区二区三区| 久久久久久久一线毛片| 免费无码AV一区二区波多野结衣| 中文熟妇人妻av在线| 国产一区二区三区怡红院| 永久天堂网 av手机版| 视频一区二区三区刚刚碰| 好男人视频免费| 日韩一区二区三区精彩视频| 四虎永久免费高清视频| 婷婷丁香五月深爱憿情网| 唐人社导航福利精品| 极品无码国模国产在线观看| 国产欧美日韩另类精彩视频| 精品国产AV最大网站| 久久久久久亚洲精品a片成人| 国产精品视频一区二区不卡| 亚洲一本二区偷拍精品| 国产精品午夜福利资源| 蜜桃视频在线免费观看一区二区 | 一本色道久久88精品综合| 国产办公室秘书无码精品99| 天天干天天干| 亚欧成人精品一区二区乱| 国产精品亚洲片在线观看麻豆| 欧美色综合天天久久综合精品| 亚洲精品一区二区三区蜜臀| 久久精品国产字幕高潮| av色蜜桃一区二区三区| 老王亚洲AV综合在线观看| 人妻聚色窝窝人体WWW一区| 国产一卡2卡三卡4卡免费网站| 昌黎县| 加勒比无码人妻东京热| 日本高清视频网站www| 日韩少妇人妻vs中文字幕| 欧美激情精品久久| 亚洲香蕉伊综合在人在线|