setTimeout的核心原理和巧用

你所不瞭解的setTimeout

小編推薦:掘金是一個高質量的技術社區,從 ECMAScript 6 到 Vue.js,性能優化到開源類庫,讓你不錯過前端開發的每個技術乾貨。各大應用市場搜索「掘金」便可下載APP,技術乾貨盡在掌握..javascript

看到了一篇不錯的文章《你會用setTimeout嗎 》,轉載過來的,改了個名字,一會兒感受搞大上了,嘎嘎。css

加了幾個關於 setTimeout 和setInterval的小知識:html

關於setInterval()和setTimeout()返回值

setInterval(),setTimeout() 會返回一個值,通常認爲是ID,將這個ID值傳遞給clearInterval(),clearTimeout() 能夠取消執行,例如:前端

js 代碼:
  1. var intervalTimer=setInterval(function(){
  2. console.log(1)
  3. },3000);
  4. console.log(intervalTimer); //通常是一個數字,Number
  5. button.onclick=function(){
  6. clearInterval(intervalTimer);
  7. };

關於setInterval()和setTimeout()中回調函數中的this

setInterval(),setTimeout() 方法是瀏覽器 window 對象提供,因此第一個參數函數中的this指向window對象,這跟變量的做用域有關:html5

js 代碼:
var a=1;
  1. var obj={
  2. a:2,
  3. b:function(){
  4. setTimeout(function(){
  5. console.log(this.a);//這裏返回的是:1;
  6. },2000);
  7. }
  8. };
  9. obj.b();

固然你能夠經過使用bind()方法來改變這個狀況:java

js 代碼:
  1. var a=1;
  2. var obj={
  3. a:2,
  4. b:function(){
  5. setTimeout(function(){
  6. console.log(this.a);//這裏返回的是:2;
  7. }.bind(this),2000);//注意這行
  8.  
  9. }
  10. };
  11. obj.b();

關於bind()方法,你能夠看這裏:http://www.css88.com/archives/5611git

關於setInterval()和setTimeout()的參數

你們都知道setInterval()和setTimeout()能夠接收兩個參數,第一個參數是須要回調的函數,必須傳入的參數,第二個參數是時間間隔,毫秒數,能夠省略,這個能夠看文章的下面,github

不傳第二個參數,瀏覽器自動配置時間,在IE,FireFox中,第一次配可能給個很大的數字,100ms上下,日後會縮小到最小時間間隔,Safari,chrome,opera則多爲10ms上下。chrome

可是我要說的固然不是這個,我要說的是setInterval()和setTimeout()能夠接收更多的參數,那麼這些參數是幹什麼用的呢?從第三個參數開始,依次用來表示第一個參數(回調函數)傳入的參數,例如:後端

js 代碼:
  1. setTimeout(function(a,b){
  2. console.log(1+a+b);//這裏打印的是:8
  3. },1000,3,4);

固然一些古老的瀏覽器是不支持的。

關於clearInterval()和clearTimeout()

clearInterval()和clearTimeout()實際上是通用的,就是說你能夠用 clearInterval() 取消 setTimeout() 執行,clearTimeout()一樣能夠取消 setInterval() 執行。

js 代碼:
  1. var intervalTimer=setInterval(function(){
  2. console.log(1)
  3. },3000);
  4. console.log(intervalTimer);
  5. button.onclick=function(){
  6. clearTimeout(intervalTimer); //注意這裏,不是clearInterval哦
  7. };

 

=============== 如下內容來源: 你會用setTimeout嗎  ===================

教科書裏面的setTimeout

定義很簡單
setTimeout() 方法用於在指定的毫秒數後調用函數或計算表達式。

普遍應用場景
定時器,輪播圖,動畫效果,自動滾動等等

上面一些應該是setTimeout在你們心中的樣子,由於咱們日常使用也不是不少。

可是setTimeout真的有那麼簡單嗎?

測試題

一個題目,若是你在一段代碼中發現下面內容

js 代碼:
  1. var startTime = new Date();
  2. setTimeout(function () {
  3. console.log(new Date() - startTime);
  4. }, 100)

請問最後打印的是多少?
我以爲正確答案是,取決於後面同步執行的js須要佔用多少時間。
MIN(同步執行的時間, 100)

再加一個題目,只有下面代碼

js 代碼:
  1. setTimeout(function () {
  2. func1();
  3. }, 0)
  4. func2();

func1和func2誰會先執行?

這個答案應該比較簡單,func2先執行,func1後面執行。

再來一題

js 代碼:
  1. setTimeout(function () {
  2. func1()
  3. }, 0)

 

js 代碼:
  1. setTimeout(function () {
  2. func1()
  3. })

有什麼差異?

0秒延遲,此回調將會放到一個能當即執行的時段進行觸發。javascript代碼大致上是自頂向下的,但中間穿插着有關DOM渲染,事件迴應等異步代碼,他們將組成一個隊列,零秒延遲將會實現插隊操做。
不寫第二個參數,瀏覽器自動配置時間,在IE,FireFox中,第一次配可能給個很大的數字,100ms上下,日後會縮小到最小時間間隔,Safari,chrome,opera則多爲10ms上下。

上面答案來自《javascript框架設計》

好了,看了上面幾個題目是否是感受setTimeout不是想象中那樣了。

setTimeout和單線程

下面是我本身的一些理解
首先須要注意javascript是單線程的,特色就是容易出現阻塞。若是一段程序處理時間很長,很容易致使整個頁面hold住。什麼交互都處理不了怎麼辦?

簡化複雜度?複雜邏輯後端處理?html5的多線程?

上面都是ok的作法,可是setTimeout也是處理這種問題的一把好手。

setTimeout一個很關鍵的用法就是分片,若是一段程序過大,咱們能夠拆分紅若干細小的塊。
例如上面的狀況,咱們將那一段複雜的邏輯拆分處理,分片塞入隊列。這樣即便在複雜程序沒有處理完時,咱們操做頁面,也是能獲得即便響應的。其實就是將交互插入到了複雜程序中執行。

換一種思路,上面就是利用setTimeout實現一種僞多線程的概念。

有個函數庫Concurrent.Thread.js 就是實現js的多線程的。

一個簡單使用的例子,引入Concurrent.Thread.js

js 代碼:
  1. Concurrent.Thread.create(function(){
  2. for (var i = 0;i<1000000;i++) {
  3. console.log(i);
  4. };
  5. });
  6. $('#test').click(function () {
  7. alert(1);
  8. });

雖然有個巨大的循環,可是這時不妨礙你去觸發alert();

是否是很厲害~

還有一種場景,當咱們須要渲染一個很複雜的DOM時,例如table組件,複雜的構圖等等,假如整個過程須要3s,咱們是等待徹底處理完成在呈現,仍是使用一個setTimeout分片,將內容一片一片的斷續呈現。

其實setTimeout給了咱們不少優化交互的空間。

如何使用

setTimeout這麼厲害,那麼咱們是須要在在項目中大量使用嗎?
我這邊的觀點是很是不建議,在咱們業務中,基本上是禁止在業務邏輯中使用setTimeout的,由於我所看到的不少使用方式都是一些問題很差解決,setTimeout做爲一個hack的方式。
例如,當一個實例尚未初始化的前,咱們就使用這個實例,錯誤的解決辦法是使用實例時加個setTimeout,確保實例先初始化。
爲何錯誤?這裏其實就是使用hack的手段
第一是埋下了坑,打亂模塊的生命週期
第二是出現問題時,setTimeout實際上是很難調試的。

我認爲正確的使用方式是,看看生命週期(可參考《關於軟件的生命週期 》),把實例化提到使用前執行。

綜上,setTimeout其實想用好仍是很困難的, 他更多的出現是在框架和類庫中,例如一些實現Promis的框架,就用上了setTimeout去實現異步。因此假如你想去閱讀一些源碼,想去造一些輪子,setTimeout仍是必不可少的工具。

相關文章
相關標籤/搜索