天天看點

你會用setTimeout嗎

定義很簡單

setTimeout() 方法用于在指定的毫秒數後調用函數或計算表達式。

廣泛應用場景

定時器,輪播圖,動畫效果,自動滾動等等

上面一些應該是setTimeout在大家心中的樣子,因為我們平常使用也不是很多。

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

測試題

一個題目,如果你在一段代碼中發現下面内容

var startTime = new Date(); setTimeout(function () {     console.log(new Date() - startTime); }, 100)

請問最後列印的是多少?

我覺得正确答案是,取決于後面同步執行的js需要占用多少時間。

MAX(同步執行的時間, 100)。

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

    func1(); }, 0) func2();

func1和func2誰會先執行?

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

再來一題

    func1()

})

有什麼差别?

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後

Concurrent.Thread.create(function(){     for (var i = 0;i<1000000;i++) {         console.log(i);     }; }); $('#test').click(function  () {     alert(1);

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

是不是很厲害~

還有一種場景,當我們需要渲染一個很複雜的DOM時,例如table元件,複雜的構圖等等,假如整個過程需要3s,我們是等待完全處理完成在呈現,還是使用一個setTimeout分片,将内容一片一片的斷續呈現。

其實setTimeout給了我們很多優化互動的空間。

如何使用

setTimeout這麼厲害,那麼我們是需要在在項目中大量使用嗎?

我這邊的觀點是非常不建議,在我們業務中,基本上是禁止在業務邏輯中使用setTimeout的,因為我所看到的很多使用方式都是一些問題不好解決,setTimeout作為一個hack的方式。

例如,當一個執行個體還沒有初始化的前,我們就使用這個執行個體,錯誤的解決辦法是使用執行個體時加個setTimeout,確定執行個體先初始化。

為什麼錯誤?這裡其實就是使用hack的手段

第一是埋下了坑,打亂子產品的生命周期

第二是出現問題時,setTimeout其實是很難調試的。

我認為正确的使用方式是,看看生命周期(可參考《關于軟體的生命周期 》),把執行個體化提到使用前執行。

綜上,setTimeout其實想用好還是很困難的, 他更多的出現是在架構和類庫中,例如一些實作Promis的架構,就用上了setTimeout去實作異步。

是以假如你想去閱讀一些源碼,想去造一些輪子,setTimeout還是必不可少的工具。

繼續閱讀