亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入理解JavaScript定時機制

2019-11-20 08:38:44
字體:
來源:轉載
供稿:網友

本文介紹了JavaScript定時機制,要理解JavaScript的定時機制,就要知道JavaScript的運行機制。

首先聲明,JavaScript是單線程運行(JavaScript引擎線程)事件驅動。

一、瀏覽器中有多個線程

一款瀏覽器中包含的最基本的線程:

1、JavaScript引擎線程。

2、定時器線程,setInterval和setTimeout會觸發這個線程。

3、瀏覽器事件觸發線程,這個線程會觸發onclick、onmousemove和其它瀏覽器事件。

4、界面渲染線程,負責渲染瀏覽器界面HTML元素。注意:在JavaScript引擎運行腳本期間,界面渲染線程都是處于掛起狀態的。也就是說當使用JavaScript對界面中的節點進行操作時,并不會立即體現出來,要等到JavaScript引擎線程空閑時,才會體現出來。(這個最后說)

5、HTTP請求線程(Ajax請求也在其中)。

以上這些線程在瀏覽器內核的控制下,相互配合,完成工作(具體我也不知道)。

二、任務隊列

我們知道JavaScript是單線程的,所有JavaScript代碼都在JavaScript引擎線程中運行。阮一峰老師的文章中叫這個線程為主線程,是一個執行棧。(以下內容也主要是根據阮一峰老師的文章理解總結。)

這些JavaScript代碼我們可以把他們看成一個個的任務,這些任務有同步任務和異步任務之分。同步任務(比如變量賦值語句,alert語句,函數聲明語句等等)直接在主線程上按順序執行,異步任務(比如瀏覽器事件觸發線程觸發的各種各樣的事件,使用Ajax返回的服務器響應等)按照時間先后順序在任務隊列(也可以叫做事件隊列、消息隊列)中排隊,等待被執行。只要主線程上的任務執行完了,就會去檢查任務隊列,看有沒有排隊等待的任務,有就讓排隊的任務進入主線程執行。

比如下面的例子:

<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>定時機制</title><style type="text/css">body{  margin: 0;  padding: 0;  position: relative;  height: 600px;}#test{  height: 30px;  width: 30px;  position: absolute;  left: 0;  top: 100px;  background-color: pink;}</style></head><body>  <div id="test">    </div><script>  var pro = document.getElementById('test');  pro.onclick = function() {    alert('我沒有立即被執行。');  };  function test() {    a = new Date();    var b=0;   for(var i=0;i<3000000000;i++) {     b++;   }   c = new Date();   console.log(c-a);  } test();</script></body></html>

在這個例子中test()函數執行完大概要8~9秒,所以當我們打開這個頁面,在8秒之前點擊粉色方塊,不會立即彈出提示框,而要等到8秒之后才彈出,而且8秒之前點擊幾次粉色框,8秒之后就彈出幾次。

我們打開這個頁面時,主線程先聲明函數test,再聲明變量pro,然后把p節點賦值給pro,然后給p節點添加click事件,并指定回調函數(掛起),然后調用test函數,執行其中的代碼。在test函數中的代碼執行期間,我們點擊了p節點,瀏覽器事件觸發線程檢測到這個事件,就把這個事件放在了任務隊列中,以便主線程上的任務(這里是test函數)執行完后,檢查任務隊列時發現這個事件并執行相應的回調函數。如果我們多次點擊,這些多次觸發的事件就按觸發時間的先后在任務隊列中排隊(可以再給另外一個元素添加點擊事件,交替點擊不同的元素來驗證)。

下面是總結的任務的運行機制:

異步執行的運行機制如下。(同步執行也是如此,因為它可以被視為沒有異步任務的異步執行。)

1、所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。

2、主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。

3、一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。

4、主線程不斷重復上面的第三步。

三、事件和回調函數

我們在給DOM元素指定事件時,都會指定一個回調函數,以便事件真的發生時執行相應的代碼。

主線程中事件的回調函數會被掛起,如果任務隊列中有正在排隊的相應的事件,當主線程檢測到時就會執行相應的回調函數。我們也可以說主線程執行異步任務,就是在執行相應的回調函數。

四、事件循環

主線程檢查任務隊列中事件的過程是循環不斷的,因此我們可以畫一個事件循環的圖:

上圖中主線程產生堆和執行棧,棧中的任務執行完畢后,主線程檢查任務隊列中由其他線程傳入的發生過的事件,檢測到排在最前面的事件,就從掛起的回調函數中找出與該事件對應的回調函數,然后在執行棧中執行,這個過程一直重復。

五、定時器

結合以上知識,下面探討JavaScript中的定時器:setTimeout()和setInterval()。

setTimeout(func, t)是超時調用,間隔一段時間后調用函數。這個過程在事件循環中的過程如下(我的理解):

主線程執行完setTimeout(func, t);語句后,把回調函數func掛起,同時定時器線程開始計時,當計時等于t時,相當于發生了一個事件,這個事件傳入任務隊列(結束計時,只計時一次),當主線程中的任務執行完后,主線程檢查任務隊列發現了這個事件,就執行掛起的回調函數func。我們指定的時間間隔t只是參考值,真正的時間間隔取決于執行完setTimeout(func, t);語句后的代碼所花費的時間,而且是只大不小。(即使我們把t設為0,也要經歷這個過程)。

setInterval(func, t)是間歇調用,每隔一段時間后調用函數。這個過程在事件循環中的過程與上面的類似,但又有所不同。

setTimeout()是經過時間t后定時器線程在任務隊列中添加一個事件(注意是一個),而setInterval()是每經過時間t(一直在計時,除非清除間歇調用)后定時器線程在任務隊列中添加一個事件,而不管之前添加的事件有沒有被主線程檢測到并執行。(實際上瀏覽器是比較智能的,瀏覽器在處理setInterval的時候,如果發現已任務隊列中已經有排隊的同一ID的setInterval的間歇調用事件,就直接把新來的事件 Kill 掉。也就是說任務隊列中一次只能存在一個來自同一ID的間歇調用的事件。)

舉個例子,假如執行完setInterval(func, t);后的代碼要花費2t的時間,當2t時間過后,主線程從任務隊列中檢測到定時器線程傳入的第一個間歇調用事件,func開始執行。當第一次的func執行完畢后,第二次的間歇調用事件早已傳入任務隊列,主線程馬上檢測到第二次的間歇調用事件,func函數又立即執行。這種情況下func函數的兩次執行是連續發生的,中間沒有時間間隔。

下面是個例子:

function test() {    a = new Date();    var b=0;   for(var i=0;i<3000000000;i++) {     b++;   }   c = new Date();   console.log(c-a); }  function test2() {   var d = new Date().valueOf();   //var e = d-a;   console.log('我被調用的時刻是:'+d+'ms');   //alert(1);  }  setInterval(test2,3000);   test();

結果:

為什么8.6秒過后沒有輸出兩個一樣的時刻,原因在上面的內容中可以找到。

執行例子中的for循環花費了8601ms,在執行for循環的過程中隊列中只有一個間歇調用事件在排隊(原因如上所述),當8601ms過后,第一個間歇調用事件進入主線程,對于這個例子來說此時任務隊列空了,可以再次傳入間歇調用事件了,所以1477462632228ms這個時刻第二次間歇調用事件(實際上應該是第三次)傳入任務隊列,由于主線程的執行棧已經空了,所以主線程立即把對應的回調函數拿來執行,第二次調用與第一次調用之間僅僅間隔了320ms(其實8601+320=8920,差不多就等于9秒了)。我們看到第三次調用已經恢復正常了,因為此時主線程中已經沒有其他代碼了,只有一個任務,就是隔一段時間執行一次間歇調用的回調函數。

用setTimeout()實現間歇調用的例子:

function test() {    a = new Date();    var b=0;   for(var i=0;i<3000000000;i++) {     b++;   }   c = new Date();   console.log(c-a);  }   function test2(){   var d = new Date().valueOf();   console.log('我被調用的時刻是:'+d+'ms');   setTimeout(test2,3000);  }  setTimeout(test2,3000); test();

 結果:

每兩次調用的時間間隔基本上是相同。想想為什么?

再看一個例子:

<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Flex布局練習</title><style type="text/css">body{  margin: 0;  padding: 0;  position: relative;  height: 600px;}#test{  height: 30px;  width: 30px;  position: absolute;  left: 0;  top: 100px;  background-color: pink;}</style></head><body>  <div id="test">    </div><script> var p = document.createElement('p'); p.style.width = '50px'; p.style.height = '50px'; p.style.border = '1px solid black';  document.body.appendChild(p); alert('ok'); </script></body></html>

這個例子的結果是提示框先彈出,然后黑色邊框的p元素才出現在頁面中。原因很簡單,就一句話:

在JavaScript引擎運行腳本期間,界面渲染線程都是處于掛起狀態的。也就是說當使用JavaScript對界面中的節點進行操作時,并不會立即體現出來,要等到JavaScript引擎線程空閑時,才會體現出來。

以上就是我對JavaScript定時機制的理解及總結,如有錯誤,希望看到的大神指正。也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩免费av一区二区| 欧洲亚洲免费在线| 欧美精品久久久久久久免费观看| 91九色单男在线观看| 国内精品400部情侣激情| 亚洲精品久久久一区二区三区| 亚洲午夜精品久久久久久久久久久久| 欧美性猛交xxxx富婆| 亚洲香蕉av在线一区二区三区| 伊人亚洲福利一区二区三区| 亚洲在线视频观看| 亚洲精品一区二区三区婷婷月| 色av中文字幕一区| 夜夜嗨av一区二区三区免费区| 国产日韩在线一区| 97视频在线观看免费| 97超碰色婷婷| 热门国产精品亚洲第一区在线| 日韩精品视频免费专区在线播放| 国产欧美一区二区三区在线看| 一区二区三区回区在观看免费视频| 亚洲欧美日韩另类| 91精品国产综合久久久久久蜜臀| 亚洲一区美女视频在线观看免费| 欧日韩不卡在线视频| 久久久久999| 黄色一区二区三区| 精品久久久久久久久久ntr影视| 97超碰色婷婷| 久久人人97超碰精品888| 亚洲日本成人女熟在线观看| 一区二区三区四区在线观看视频| 国产精品色婷婷视频| 日韩国产中文字幕| 色综合伊人色综合网| 久久久久国产一区二区三区| 国产欧美婷婷中文| 国产精品国内视频| 羞羞色国产精品| 国产欧美一区二区三区四区| 国产日韩欧美中文在线播放| 高跟丝袜一区二区三区| 久久亚洲私人国产精品va| 日韩国产欧美精品一区二区三区| 久久亚洲电影天堂| 午夜精品免费视频| 日韩美女在线播放| 午夜精品免费视频| 久久精品国产v日韩v亚洲| 亚洲精品动漫久久久久| 色播久久人人爽人人爽人人片视av| 97精品一区二区视频在线观看| 久久久免费高清电视剧观看| 亚洲精品丝袜日韩| 中文字幕欧美日韩| 亚洲高清久久网| 91精品国产91久久久久| 欧美性xxxx极品hd欧美风情| 中文字幕日韩欧美在线| 久久99久久99精品免观看粉嫩| 久热精品在线视频| 日本免费在线精品| 欧美激情一二三| 在线观看久久久久久| 精品国产欧美一区二区五十路| 视频在线观看一区二区| 亚洲无av在线中文字幕| 亚洲人成电影网站| 欧美电影在线观看| 国产成人精品综合久久久| 国产日产欧美a一级在线| 日韩欧美主播在线| 911国产网站尤物在线观看| 在线日韩中文字幕| 国产精品久久一区| 色综久久综合桃花网| 中文字幕亚洲自拍| 韩剧1988在线观看免费完整版| 中文字幕亚洲无线码在线一区| 国产精品主播视频| 欧洲s码亚洲m码精品一区| 欧美二区乱c黑人| 国产精品一区二区三区毛片淫片| 亚洲福利视频专区| 国产91精品久久久久久久| 在线视频免费一区二区| 亚洲高清久久久久久| 久久这里只有精品99| 日韩av最新在线| 亚洲国产一区自拍| 狠狠操狠狠色综合网| 国产精品美女呻吟| 热久久免费国产视频| 亚洲国产精品va在线看黑人动漫| 日韩精品亚洲元码| 久久久久久久av| 国产精品自产拍在线观看| 38少妇精品导航| 在线观看中文字幕亚洲| 日韩视频―中文字幕| 欧洲亚洲免费在线| 国产综合在线看| 欧美日韩国产二区| 庆余年2免费日韩剧观看大牛| 日韩精品久久久久久久玫瑰园| 亚洲国产精品一区二区久| 亚洲成av人影院在线观看| 久久99热这里只有精品国产| 亚洲国产私拍精品国模在线观看| 日韩人在线观看| 国产欧美va欧美va香蕉在线| 亚洲欧美国产日韩中文字幕| 亚洲r级在线观看| 亚洲美女激情视频| 日本欧美中文字幕| 亚洲精品xxx| 91麻豆国产语对白在线观看| 国产精品中文字幕久久久| 丝袜情趣国产精品| 亚洲精品videossex少妇| 久久精品视频99| 国产精品精品视频| 91亚洲精品一区二区| 久久成人在线视频| 国产ts一区二区| 久久久综合免费视频| 亚洲白虎美女被爆操| 国产精品久久久久aaaa九色| 欧美精品在线观看| 亚洲精品日韩久久久| 国产精品视频资源| 久久久中文字幕| 国产精品久久综合av爱欲tv| 7m精品福利视频导航| 久久中文字幕一区| 欧美性xxxx18| 日本成熟性欧美| 这里只有精品在线观看| 国产日本欧美一区二区三区| 久久精品国产亚洲7777| 国产精品精品视频| 日韩在线观看网站| 国产精品久久久久久av福利软件| 国产国语刺激对白av不卡| 欧美大学生性色视频| 久久久影视精品| 中文字幕av一区二区| 亚洲风情亚aⅴ在线发布| 成人精品aaaa网站| 亚洲欧美在线免费观看| 国产精选久久久久久| 精品一区二区三区三区| 欧美xxxx综合视频| 91久久久在线| 国产中文字幕日韩| 亚洲丁香久久久| 亚洲乱码国产乱码精品精天堂| 亚洲缚视频在线观看| 国产精品视频1区| 日韩国产欧美精品在线| www国产精品视频| 欧美大秀在线观看| 98视频在线噜噜噜国产| 国产欧美久久一区二区|