中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中setTimeOut的使用方法

發布時間:2020-07-03 13:32:09 來源:億速云 閱讀:223 作者:元一 欄目:web開發

本篇文章為大家展示了JavaScript中setTimeOut的使用方法,代碼簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

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

code (必需):(本意是代碼的意思)要調用的函數后要執行的 JavaScript 代碼串。
millisec(必需):在執行代碼前需等待的毫秒數。
注意:
setTimeout() 只執行 code 一次。如果要多次調用,請使用 setInterval() 或者讓 code 自身再次調用 setTimeout()。

看到這樣一個說明,我們明白了它就是一個定時器,我們設定的函數就是一個"鬧鐘",時間到了它就會去執行.然而聰明的你不禁有這樣一個疑問,如果是settimeout(fn,0)呢?按照定義的說明,它是否會立馬執行?實踐是檢驗真理的唯一標準,讓我們來看看下面的實驗

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <script>
        alert(1); 
        setTimeout("alert(2)", 0); 
        alert(3); 
    </script>
</body>
</html>

這是一個很簡單的實驗,如果settimeout(0)會立即執行,那么這里的執行結果就應該是1->2>3  . 然而實際的結果卻是1->3->2. 這說明了settimeout(0)并不是立即執行.同時讓我們對settimeout的行為感到很詭異.

js引擎是單線程執行的

我們先把上面的問題放一放.從js語言的設計上來看看是否能找到蛛絲馬跡.

我們發現js語言設計的一個很重要的點是,js是沒有多線程的.js引擎的執行是單線程執行.這個特性曾經困擾我很久,我想不明白既然js是單線程的,那么是誰來為定時器計時的?是誰來發送ajax請求的?我陷入了一個盲區.即將js等同于瀏覽器.我們習慣了在瀏覽器里面執行代碼,卻忽略了瀏覽器本身.js引擎是單線程的,可是瀏覽器卻可以是多線程的,js引擎只是瀏覽器的一個線程而已.定時器計時,網絡請求,瀏覽器渲染等等.都是由不同的線程去完成的. 口說無憑,咱們依然看一個例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
</body>
<script>
    var isEnd = true;
    window.setTimeout(function () {
        isEnd = false;//1s后,改變isEnd的值
    }, 1000);
    while (isEnd);
    alert('end');
</script>
</html>

isEnd默認是true的,在while中是死循環的.最后的alert是不會執行的. 我添加了一個定時器,1秒后將isEnd改為false. 如果說js引擎是多線程的,那么在1秒后,alert就會被執行.然而實際情況是,頁面會永遠死循環下去.alert并沒有執行.這很好的證明了,settimeout并不能作為多線程使用.js引擎執行是單線程的.

event loop

從上面的實驗中,我們更加疑惑了,settimeout到底做了什么事情呢?

原來還是得從js語言的設計上尋找答案.

JavaScript中setTimeOut的使用方法

js引擎單線程執行的,它是基于事件驅動的語言.它的執行順序是遵循一個叫做事件隊列的機制.從圖中我們可以看出,瀏覽器有各種各樣的線程,比如事件觸發器,網絡請求,定時器等等.線程的聯系都是基于事件的.js引擎處理到與其他線程相關的代碼,就會分發給其他線程,他們處理完之后,需要js引擎計算時就是在事件隊列里面添加一個任務. 這個過程中,js并不會阻塞代碼等待其他線程執行完畢,而且其他線程執行完畢后添加事件任務告訴js引擎執行相關操作.這就是js的異步編程模型.

如此我們再回過頭來看settimeout(0)就會恍然大悟.js代碼執行到這里時,會開啟一個定時器線程,然后繼續執行下面的代碼.該線程會在指定時間后往事件隊列里面插入一個任務.由此可知settimeout(0)里面的操作會放在所有主線程任務之后. 這也就解釋了為什么第一個實驗結果是1->3-2 .

由此可見官方對于settimeout的定義是有迷惑性的.應該給一個新的定義:

在指定時間內, 將任務放入事件隊列,等待js引擎空閑后被執行.

js引擎與GUI引擎是互斥的

談到這里,就不得不說瀏覽器的另外一個引擎---GUI渲染引擎. 在js中渲染操作也是異步的.比如dom操作的代碼會在事件隊列中生成一個任務,js執行到這個任務時就會去調用GUI引擎渲染.

js語言設定js引擎與GUI引擎是互斥的,也就是說GUI引擎在渲染時會阻塞js引擎計算.原因很簡單,如果在GUI渲染的時候,js改變了dom,那么就會造成渲染不同步. 我們需要深刻理解js引擎與GUI引擎的關系,因為這與我們平時開發息息相關,我們時長會遇到一些很奇葩的渲染問題.看這個例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <table border=1>
        <tr><td><button id='do'>Do long calc - bad status!</button></td>
            <td><p id='status'>Not Calculating yet.</p></td>
        </tr>
        <tr><td><button id='do_ok'>Do long calc - good status!</button></td>
            <td><p id='status_ok'>Not Calculating yet.</p></td>
        </tr>
    </table>    
<script>
function long_running(status_p) {
    var result = 0;
    for (var i = 0; i < 1000; i++) {
        for (var j = 0; j < 700; j++) {
            for (var k = 0; k < 300; k++) {
                result = result + i + j + k;
            }
        }
    }
    document.querySelector(status_p).innerHTML = 'calclation done' ;
}
document.querySelector('#do').onclick = function () {
    document.querySelector('#status').innerHTML = 'calculating....';
    long_running('#status');
};
document.querySelector('#do_ok').onclick = function () {
    document.querySelector('#status_ok').innerHTML = 'calculating....';
    window.setTimeout(function (){ long_running('#status_ok') }, 0);
};
</script>
</body>
</html>

我們希望能看到計算的每一個過程,我們在程序開始,計算,結束時,都執行了一個dom操作,插入了代表當前狀態的字符串,Not Calculating yet.和calculating....和calclation done.計算中是一個耗時的3重for循環. 在沒有使用settimeout的時候,執行結果是由Not Calculating yet 直接跳到了calclation done.這顯然不是我們希望的.而造成這樣結果的原因正是js的事件循環單線程機制.dom操作是異步的,for循環計算是同步的.異步操作都會被延遲到同步計算之后執行.也就是代碼的執行順序變了.calculating....和calclation done的dom操作都被放到事件隊列后面而且緊跟在一起,造成了丟幀.無法實時的反應.這個例子也告訴了我們,在需要實時反饋的操作,如渲染等,和其他相關同步的代碼,要么一起同步,要么一起異步才能保證代碼的執行順序.在js中,就只能讓同步代碼也異步.即給for計算加上settimeo0t.

settimeout(0)的作用

不同瀏覽器的實現情況不同,HTML5定義的最小時間間隔是4毫秒. 使用settimeout(0)會使用瀏覽器支持的最小時間間隔.所以當我們需要把一些操作放到下一幀處理的時候,我們通常使用settimeout(0)來hack.

requestAnimationFrame

這個函數與settimeout很相似,但它是專門為動畫而生的.settimeout經常被用來做動畫.我們知道動畫達到60幀,用戶就無法感知畫面間隔.每一幀大約16毫秒.而requestAnimationFrame的幀率剛好是這個頻率.除此之外相比于settimeout,還有以下的一些優點:

  • requestAnimationFrame 會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率,一般來說,這個頻率為每秒60幀,每幀大約16毫秒.

  • 在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或回流,這當然就意味著更少的的cpu,gpu和內存使用量。

  • 但它優于setTimeout/setInterval的地方在于它是由瀏覽器專門為動畫提供的API,在運行時瀏覽器會自動優化方法的調用,并且如果頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷。

總結:

  1. 瀏覽器的內核是多線程的,它們在內核制控下相互配合以保持同步,一個瀏覽器至少實現三個常駐線程:javascript引擎線程,GUI渲染線程,瀏覽器事件觸發線程。

  2. javascript引擎是基于事件驅動單線程執行的.JS引擎一直等待著任務隊列中任務的到來,然后加以處理,瀏覽器無論什么時候都只有一個JS線程在運行JS程序。

  3. 當界面需要重繪(Repaint)或由于某種操作引發回流(reflow)時,該線程就會執行。但需要注意 GUI渲染線程與JS引擎是互斥的,當JS引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執行。

  4. 當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎當前執行的代碼塊如setTimeOut、也可來自瀏覽器內核的其他線程如鼠標點擊、AJAX異步請求等,但由于JS的單線程關系所有這些事件都得排隊等待JS引擎處理。

上述內容就是JavaScript中setTimeOut的使用方法,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

云和县| 温州市| 元谋县| 云南省| 汉川市| 天气| 兰溪市| 巍山| 广宗县| 平阴县| 阳春市| 山阳县| 通山县| 武夷山市| 阳高县| 札达县| 通海县| 巴林左旗| 若尔盖县| 阿拉善左旗| 贵港市| 五华县| 云林县| 太和县| 武冈市| 丁青县| 桃园县| 镇坪县| 岳阳市| 平罗县| 贵德县| 彩票| 洛隆县| 江孜县| 宣恩县| 女性| 怀化市| 清镇市| 吉安县| 阿拉尔市| 色达县|