setTimeout你知多少

2022-03-25 04:51:52 字數 3902 閱讀 8968

假期這麼快就結束了,其實對我來說沒什麼影響,因為我一周才兩節課,對於課多的同學來說,我天天在休假,不要羨慕喲~  但休假並不代表閒著,還是得苦逼的編**,唉。。一入程式深似海。。

不管學得多少,還是總結一些,還是一些小問題。當然也是很重要的,好! 廢話少說該入正題了。

上次提到非同步,當時說,不知道是啥就去查漢語字典,但後來發現查了字典還是不會。回顧一下

js哪些操作是非同步的???settimeout、setinterval、ajax、各種事件處理,才疏學淺,我就知道這些,誰還知道有哪些,勞煩告訴我,學習學習。

for(var i=0; i<5; i++),100);

} //答案是: 5 5 5 5

for(var i=0; i<5; i++),100);

})(i);

}; 答案是 0 1 2 3 4

為什麼是這個答案,重申一遍:作用域的關係。具體解釋作用域與執行環境無關,由定義時決定並一步一步往上查詢。上述兩個例子 執行匿名函式時執行的是:

function

() 而i等於多少? 我們從定義處查詢 settimeout中沒有i 在往上一層就到了全域性中,此時i已經等於5 所以答案是全是5

function

() 而j等於多少? 我們還是從定義處查詢 settimeout中沒有j 在往上一層就到了上乙個形參為j的匿名函式,此時j是形參,在定義settimeout中的函式時,j的形參依次被傳入實參i,依次為0,1,2,3,4 所以答案是全是0,1,2,3,4

換湯不換藥,找個例子實驗一下:

[1,2,3,4,5].foreach(function

(elem), 200);

}) 答案是多少?? 5,5,5,5?? 1,1,1,1?? 1,2,3,4,5還是??? 答案是1,2,3,4,5 如果錯了的話,再把前面的例子,文字看看。

繼續,再來一道:

for(var i=0; i<5; i++), math.random()*1000);

})(i);

} //這個答案是什麼呢?? 是0,1,2,3,4還是什麼??? 好好想想。

根據前面的分析,先找定義處 依次往上查詢,到function(j)這個函式時,已經把實參i傳進來了,所以答案是0,1,2,3,4  yes or no?? 答案是錯誤的。為什麼?

實參i確實把值傳進來了,該段**就等價於

settimeout(function

(), math.random()*1000);

settimeout(

function

(), math.random()*1000);

settimeout(

function

(), math.random()*1000);

settimeout(

function

(), math.random()*1000);

settimeout(

function

(), math.random()*1000);

此時只看這段** 答案是多少??? 大家肯定會說是亂序的,跟 (math.random()*1000) 值有關,yes 你答對了。 所以上面那個答案是亂序的0,1,2,3,4

那麼,下面那個**呢?

settimeout(function

(),100);

settimeout(

function

(),200);

很多人肯定會說,這還用說嗎? 不用想都知道是15, 5。對,但是就這段**而言,這個15,5   從等待到執行(此處執行時間忽略不計)一共是花了300ms還是200ms呢? 答案是200ms,為什麼?剛剛開頭就說過,settimeout()函式是非同步的,非同步有個的特點就是併發性,在同時定義這兩個函式時,他們同時在等待,放入到訊息佇列中,所以100ms後第乙個函式放入時,第二個函式已經等了100ms,所以兩個函式一共等了200ms。 總之一句話:非同步具有併發性,與順序無關(時間相同或者相近的情況下有關),與時間的快慢有關,請記住它。

這裡還要提的是:關於定時器中的時間,指的是何時將定時器的**新增到佇列中,而不是何時實際執行**,只能表示它會盡快執行。

如 :

document.onclick = function

(),250);

}; //如果onclick事件處理程式執行了300ms 那麼定時器**至少要在定時器設定後的300ms才會被執行,也就是34至少要在300ms後輸出。

大家馬上就想到,如果是這樣的話,setinterval()就會出現一種情況:在**再次被新增到佇列之前沒完成執行,導致定時器**連續執行好幾次,沒有停頓。幸好,js引擎夠聰明,能避免這個問題,如何避免?當使用setinterval()時,僅當沒有該定時器的任何其他**例項時,才將定時器**新增到佇列中,這樣確保了定時器**加入到佇列中的最小時間間隔為指定間隔,注意是新增到佇列中的最小時間間隔而不是執行。但是。。這個規則有兩個問題:1.某些間隔會被跳過,2.多個定時器的**執行之間的間隔可能會比預期的少。舉個例子:

某個onclick事件處理程式使用setinterval()設定了乙個200ms間隔的重複定時器,如果事件程式花了300ms多一點的時間完成,定時器也花差不多的時間,就會出現上述兩個問題。

如圖:

此圖來自《js高階程式設計》這本書強烈推薦閱讀。。。

我們分析一下:在5ms時建立了間隔為200ms的定時器,第乙個定時器在205ms後被新增到佇列中,但直到onclik執行完才執行,執行時,在405ms處第二個定時器又被新增到佇列中,在605ms第三個定時器要新增到佇列中,但此時第二個定時器還沒被執行,所以第三個不會被新增,同時在第乙個定時器執行完之後第二個立即執行,所以第乙個定時器和第二個定時器執行的間隔小於200ms,其實此處就是從第乙個執行結束到第二個開始執行沒有間隔。

有人可能想到這樣的話js引擎並沒有解決定時器**連續執行問題,確實,但其實js引擎這種做法(在僅當沒有該定時器的任何其他**例項時,才將定時器**新增到佇列中),減少了連續的次數,不至於堆積太多。

為了避免這2個缺點,可以使用如下模式使用鏈式settimeout()呼叫。

settimeout(function

(), interval);

每次函式執行時建立乙個新的定時器,這樣的好處:在前乙個定時器**執行完之前,不會向佇列插入新的定時器**,確保不會有任何缺失的間隔,而且,它可以保證在下一次定時器**執行之前,至少要等待指定的間隔,避免了連續的執行。詳細請看《js高階程式設計》這本書。

關於settimeout()函式還有一點就是:

大家都知道dom比非dom互動要更多的記憶體和cpu時間,如果連續進行過多的dom相關操作可能會導致瀏覽器掛起甚至崩潰。如resize事件,為了繞開這個問題我們可以使用settimeout();

模式如下:

var processor =,

process: function(), 100);

}

};

processor.process();

時間間隔設為100ms,表示最後一次呼叫process()之後至少100ms後才會被呼叫performprocessing(),如果100ms之內呼叫了process()共20次,performprocessing()仍只會被呼叫一次。因為,在100ms之內定時器都沒開始執行,呼叫process()只會清除前一次的,最後只剩下最後一次settimeout()。也就是說performprocessing()仍只會被呼叫一次。

這個過程叫做函式節流,基本思想是:某個**不可以在沒有間斷的情況連續重複執行。今天先暫且消化這些。

const你知多少?

const關鍵字至少有下列 n個作用 1 欲阻止乙個變數被改變,可以使用 const關鍵字。在定義該 const變數時,通常需要對它進行初始化,因為以後就沒有機會再去改變它了 2 對指標來說,可以指定指標本身為 const,也可以指定指標所指的資料為 const,或二者同時指定為 const 3 在...

FLEX 開發領域你知多少?

對於flex flash 本身 來講尤其 是flex 給提供很多標準組建對於初學者來說使用起來和開發起來很簡單。最典型的應用就是做個 應用系統,樹 表單 提交這類的。但是如果你只會掌握這些你就說你精通flex或者會flex那我就只能無奈了。我本身來講做過幾個方向領域的flex研究和開發一般來講。可大...

FLEX 開發領域你知多少

flex 開發領域你知多少?2010年06月29日 對於flex flash 本身 來講尤其 是flex 給提供很多標準組建對於初學者來說使用起來和開發起來很簡單。最典型的應用就是做個 應用系統,樹 表單 提交這類的。但是如果你只會掌握這些你就說你精通flex或者會flex那我就只能無奈了。我本身來...