摘要:設置和清除定時器直接引用忍者秘籍中的圖片注意定時器的時間間隔設為,也會有幾毫秒的延遲。以上參考資料忍者秘籍第章馴服線程和定時器
前言
前段時間剛看完《JS忍者秘籍》,雖說是15年出版的,有些東西是過時了,但像對原型鏈、閉包、正則、定時器之類的機制卻是不會過時的,里面很多東西都講的很細,還是值得一讀的,本文將對這本書中對定時器機制的部分進行詳細的解析,如果喜歡的話可以點波贊/關注,支持一下,希望大家看完本文可以有所收獲。
個人博客了解一下:obkoro1.com準備
閱讀本文之前,推薦先閱讀Js 的事件循環(Event Loop)機制以及實例講解這篇文章來理解背后發生的事情,本文對事件循環機制不會很仔細的講解。
定時器解決的問題:由于JS的單線程特性,定時器提供了一種跳出單線程限制的方法,即讓一段代碼在一定毫秒之后,再異步執行。
設置和清除定時器:直接引用忍者秘籍中的圖片:
注意:定時器的時間間隔設為0,也會有幾毫秒的延遲。
在使用setTimeout和setInterval的時候最好將其賦值給一個變量,以便取消定時器。
在使用Vue的時候,setTimeout和setInterval的this指向的是window對象,訪問不到組件數據以及方法。
在使用Vue的時候,路由跳轉并不會銷毀setInterval,但是組件已經銷毀了,這會導致問題。
在執行線程中setTimeout/setInterval無法保證準時執行回調函數的。
setInterval調用有可能會被廢棄以及setInterval的連續執行
第三點和第四點的解決方法可以參考我之前寫的Vue 實踐過程中的幾個問題。
接下來要講的是第五點和第六點,這兩點是最重要,也是本文要重點解析的內容。
執行線程中的定時器執行下面來看忍者秘籍中的栗子:
讓我們看看這里發生了什么事情:
首先在0毫秒的時候有一個持續18毫秒的js代碼塊要執行。
然后在0毫秒的時候設了兩個10毫秒延遲的定時器,setTimeout以及setInterval,setTimeout先設定。
在第6毫秒的時候有一個發生了鼠標單擊事件。
事件排隊。同時發生了這么多事情,由于js的單線程特性,當線程正在執行狀態,有異步事件觸發時,它就會排隊,并且在線程空閑時才進行執行。
這里的異步事件包括:鼠標單擊,定時器觸發,ajax請求、promise等事件。
讓我們回到栗子中:
栗子中首先有一個18毫秒的代碼塊要執行,在這18毫秒中只能執行這段代碼塊,其他事件觸發了之后只能排隊等待執行。
在代碼塊還在運行期間,第6毫秒的時候,發生了一個鼠標單擊事件,以及第10毫秒時的setTimeout和setInterval兩個處理程序,這三個事件不能立即執行,而是被添加到等待執行的隊列中。
先進先出(先排隊的先執行)18毫秒的時候代碼塊結束執行,有三個任務在排隊等待執行,根據先進先出的原則,此時會先執行click事件,setTimeout和setInterval將繼續排隊等待執行。
setInterval調用被廢棄在click事件執行時,第20毫秒處,第二個setInterval也到期了,因為此時已經click事件占用了線程,所以setInterval還是不能被執行,并且因為此時隊列中已經有一個setInterval正在排隊等待執行,所以這一次的setInterval的調用將被廢棄。
瀏覽器不會對同一個setInterval處理程序多次添加到待執行隊列。
setTimeout/setInterval無法保證準時執行回調函數click事件在第28毫秒處結束執行,有兩個任務(setTimeout和setInterval)正在等待執行,遵循先進先出的原則,setTimeout早于setInterval設定,所以先執行setTimeout。
so:我們期望在第10毫秒處執行的setTimeout處理程序,最終會在第28毫秒處才開始執行,這就是上文提到的setTimeout/setInterval無法保證準時執行回調函數。
在30毫秒處,setInterval又觸發了,因為隊列中已經有setInterval在排隊,所以這次的觸發又作廢了。
setInterval的連續執行setTimeout執行結束,在第36毫秒處,隊列中的setInterval處理程序才開始執行,setInterval需要執行6毫秒。
在第40毫秒的時候setInterval再次觸發,因為此時上一個setInterval正在執行期間,隊列中并沒有setInterval在排隊,這次觸發的setInterval將進入隊列等候。
所以:setInterval的處理時長不能比設定的間隔長,否則setInterval將會沒有間隔的重復執行
第42毫秒的時候,第一個setInterval結束,然后隊列中的setInterval立即開始執行,在48毫秒的時候完成執行。然后50毫秒的時候再次觸發setInterval,此時沒有任務在排隊,將會立即執行。
setTimeout按照一定的間隔周期性的觸發定時器。上文說了,setInterval的處理時長不能比設定的間隔長,否則setInterval將會沒有間隔的重復執行。
但是對這個問題,很多情況下,我們并不能清晰的把控處理程序所消耗的時長,為了我們能按照一定的間隔周期性的觸發定時器,忍者秘籍中提供了下面這種使用方法:
// 實際上我不止在忍者秘籍中見過,在很多地方都見過這種技術。 setTimeout(function repeatMe(){ // do something setTimeout(repeatMe,10); // 執行完處理程序的內容后,在末尾再間隔10毫秒來調用該程序,這樣就能保證一定是10毫秒的周期調用 },10)忍者秘籍中關于定時器的其他知識:
定時器不能非常細粒化的控制執行的時間,書中建議在15ms以上。
可以使用定時器來分解長時間運行的任務,這里可以自行谷歌。
任務隊列只有排隊這么簡單嗎?事實上,關于任務隊列并不是只有簡單的排隊而已,忍者秘籍中提到為了方便,使用了這個概念,如果希望能更清晰的了解背后的機制,再次推薦閱讀一下:Js 的事件循環(Event Loop)機制以及實例講解,
結語這上面所有一切,都是由js單線程特性導致的,所以會有事件排隊、先進先出、setInterval調用被廢棄、定時器無法保證準時執行回調函數以及出現setInterval的連續執行,時刻記住這一特性,很多關于事件執行順序的問題都能想的通,并且找出解決方法。
希望看完的朋友可以點個喜歡/關注,您的支持是對我最大的鼓勵。個人blog and 掘金個人主頁,如需轉載,請放上原文鏈接并署名。碼字不易,感謝支持!本人寫文章本著交流記錄的心態,寫的不好之處,不撕逼,但是歡迎指點。
如果喜歡本文的話,歡迎關注我的訂閱號,漫漫技術路,期待未來共同學習成長。
以上2018.6.17
參考資料:JS忍者秘籍第8章:馴服線程和定時器
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95598.html
摘要:閉包閉包的特點就是內部匿名函數可以訪問外部函數作用域的變量和方法變量對象。閉包的主要表現形式就是匿名函數,但是兩者并不是等價的。中是沒有塊級作用域的,為了在中引入塊級作用域,可以使用匿名函數模擬塊級作用域。 在介紹閉包之前,首先解釋在隨后的測試實例中會使用的assert測試函數,這個方法有別于alert()測試,有很大的改進。 assert()測試方法 #...
摘要:閉包閉包的特點就是內部匿名函數可以訪問外部函數作用域的變量和方法變量對象。閉包的主要表現形式就是匿名函數,但是兩者并不是等價的。中是沒有塊級作用域的,為了在中引入塊級作用域,可以使用匿名函數模擬塊級作用域。 在介紹閉包之前,首先解釋在隨后的測試實例中會使用的assert測試函數,這個方法有別于alert()測試,有很大的改進。 assert()測試方法 #...
摘要:對于執行時間過長的腳本,有的瀏覽器會彈出警告,說頁面無響應。一個代碼塊長時間運行,將會導致其他任何任務都必須等待。而其他瀏覽器,比如上的瀏覽器,將默認終止運行時間超過秒鐘的腳本。利用定時器來分解任務,關鍵點有兩個。實際上每行耗時約左右。 對于執行時間過長的腳本,有的瀏覽器會彈出警告,說頁面無響應。有的瀏覽器會直接終止腳本。總而言之,瀏覽器不希望某一個代碼塊長時間處于運行狀態,因為js是...
摘要:我們需要知道的是,對于而言,匿名函數是一個很重要且具有邏輯性的特性。通常,匿名函數的使用情況是創建一個供以后使用的函數。截圖自忍者秘籍通過完善之前對匿名函數的粗略定義,我們可以修復解決這個問題。 從名字即可看書,此篇博客總結與《JavaScript忍者秘籍》。對于JavaScript來說,函數為第一類型對象。所以這里,我們主要是介紹JavaScript中函數的運用。 系列博客地址:h...
摘要:第二例這段代碼是用來做將斷言測試分組的,代碼多了些,問題自然也更多了些。首先作者使用了自執行方法封閉了作用域,使用來指向全局對象,進而產生全局可訪問的屬性。沒想到,久負盛名,豆瓣評分的大作,作者的光環,代碼風格居然是如此的不謹慎。 第二章中 作者給了幾個簡單的斷言例子,思路與方向是極不錯的,創造JQ的大神,思想高度絕對無法讓我質疑的,但是代碼的功底細節,實在是讓人不敢恭維。 第一例: ...
閱讀 2688·2023-04-25 17:21
閱讀 2550·2021-11-23 09:51
閱讀 2836·2021-09-24 10:32
閱讀 3768·2021-09-23 11:33
閱讀 1973·2019-08-30 15:44
閱讀 3452·2019-08-30 11:18
閱讀 3518·2019-08-30 10:53
閱讀 622·2019-08-26 13:25