你真會用setTimeout嗎?

教科書裏面的setTimeout

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

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

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

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

測試題git

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

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

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

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

setTimeout(function () {
        func1();
    }, 0)
    func2();

func1和func2誰會先執行? 瀏覽器

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

再來一題

setTimeout(function () {
        func1()
    }, 0)

setTimeout(function () {
        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仍是必不可少的工具。

微信公衆號

圖片描述

博客地址

http://tangguangyao.github.io/

相關文章
相關標籤/搜索