定義很簡單
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還是必不可少的工具。