成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

前端進階之JS運行原理和機制詳解

開發 前端
JavaScript語言的一大特點就是單線程,也就是說,同一個時間只能做一件事。那么,為什么JavaScript不能有多個線程呢?這樣能提高效率啊。

[[422053]]

前言

之前我們一直說要介紹下前端的知識點,一直沒空總結,這不來了;

js運行機制,來一篇總結

一、js的基礎知識點介紹

  • js作為瀏覽器腳本語言,它的主要用途是與用戶互動,以及操作DOM,因此js是單線程,也避免了同時操作同一個DOM的矛盾問題;
  • 為了利用多核CPU的計算能力,H5的Web Worker實現的“多線程”實際上指的是“多子線程”,完全受控于主線程,且不允許操作DOM;
  • js引擎存在monitoring process進程,會持續不斷的檢查主線程執行棧是否為空,一旦為空,就會去Event Queue那里檢查是否有等待被調用的函數。這個過程是循環不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環);
  • 所有同步任務都在主線程上執行,形成一個執行棧(execution context stack);
  • 如果在微任務執行期間微任務隊列加入了新的微任務,會將新的微任務加入隊列尾部,之后也會被執行;

二、相關概念

1、JS為什么是單線程的?

  • JavaScript語言的一大特點就是單線程,也就是說,同一個時間只能做一件事。那么,為什么JavaScript不能有多個線程呢?這樣能提高效率啊。
  • JavaScript的單線程,與它的用途有關。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,這時瀏覽器應該以哪個線程為準?
  • 所以,為了避免復雜性,從一誕生,JavaScript就是單線程,這已經成了這門語言的核心特征,將來也不會改變;
  • 為了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標準并沒有改變JavaScript單線程的本質;

2、JS為什么需要異步?

如果JS中不存在異步,只能自上而下執行,如果上一行解析時間很長,那么下面的代碼就會被阻塞。對于用戶而言,阻塞就意味著"卡死",這樣就導致了很差的用戶體驗;

3、JS單線程又是如何實現異步的呢?

既然JS是單線程的,只能在一條線程上執行,又是如何實現的異步呢?

是通過的事件循環(event loop),理解了event loop機制,就理解了JS的執行機制。

4、任務隊列

  • "任務隊列"是一個事件的隊列(也可以理解成消息的隊列),IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務可以進入"執行棧"了。主線程讀取"任務隊列",就是讀取里面有哪些事件;
  • "任務隊列"中的事件,除了IO設備的事件以外,還包括一些用戶產生的事件(比如鼠標點擊、頁面滾動等等)。只要指定過回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。
  • 所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數;
  • "任務隊列"是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動進入主線程。但是,由于存在后文提到的"定時器"功能,主線程首先要檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。
  • 讀取到一個異步任務,首先是將異步任務放進事件表格(Event table)中,當放進事件表格中的異步任務完成某種事情或者說達成某些條件(如setTimeout事件到了,鼠標點擊了,數據文件獲取到了)之后,才將這些異步任務推入事件隊列(Event Queue)中,這時候的異步任務才是執行棧中空閑的時候才能讀取到的異步任務;

5、Event Loop

  • 主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環);
  • Event Loop是javascript的執行機制

6、setTimeout(fn,0)

  • setTimeout(fn,0)的含義是,指定某個任務在主線程最早可得的空閑時間執行,也就是說,盡可能早得執行。它在"任務隊列"的尾部添加一個事件,因此要等到同步任務和"任務隊列"現有的事件都處理完,才會得到執行。
  • HTML5標準規定了setTimeout()的第二個參數的最小值(最短間隔),不得低于4毫秒,如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。另外,對于那些DOM的變動(尤其是涉及頁面重新渲染的部分),通常不會立即執行,而是每16毫秒執行一次。這時使用requestAnimationFrame()的效果要好于setTimeout()。
  • 需要注意的是,setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執行棧)執行完,主線程才會去執行它指定的回調函數。要是當前代碼耗時很長,有可能要等很久,所以并沒有辦法保證,回調函數一定會在setTimeout()指定的時間執行

三、js執行機制介紹

1、javascript的同步和異步

  • 單線程就意味著,所有任務需要排隊,前一個任務結束,才會執行后一個任務。如果前一個任務耗時很長,后一個任務就不得不一直等著。
  • 如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閑著的,因為IO設備(輸入輸出設備)很慢(比如Ajax操作從網絡讀取數據),不得不等著結果出來,再往下執行。
  • JavaScript語言的設計者意識到,這時主線程完全可以不管IO設備,掛起處于等待中的任務,先運行排在后面的任務。等到IO設備返回了結果,再回過頭,把掛起的任務繼續執行下去。
  • 于是,所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。

  • 同步和異步任務分別進入不同的執行"場所",同步的進入主線程,異步的進入Event Table并注冊函數。
  • 當Event Table中指定的事情完成時,會將這個函數移入Event Queue。
  • 主線程內的任務執行完畢為空,會去Event Queue讀取對應的函數,進入主線程執行。
  • 上述過程會不斷重復,也就是常說的Event Loop(事件循環)。
  • 我們不禁要問了,那怎么知道主線程執行棧為空啊?js引擎存在monitoring process進程,會持續不斷的檢查主線程執行棧是否為空,一旦為空,就會去Event Queue那里檢查是否有等待被調用的函數;

2、JavaScript的宏任務與微任務

你是否覺得同步異步的執行機制流程就是JavaScript執行機制的全部?不是的,JavaScript除了廣義上的的同步任務何異步任務,其對任務還有更精細的定義:

  • macro-task(宏任務):包括整體代碼script,setTimeout,setInterval
  • micro-task(微任務):Promise,process.nextTick

不同類型的任務會進入對應的Event Queue。

事件循環的順序,決定js代碼的執行順序。進入整體代碼(宏任務)后,開始第一次循環。接著執行所有的微任務。然后再次從宏任務開始,找到其中一個任務隊列執行完畢,再執行所有的微任務。

3、實例來說明JavaScript的執行機制

3.1、同步

  1. console.log(1); 
  2. console.log(2); 
  3. console.log(3); 
  4. /* 
  5.     執行結果:1、2、3 
  6.     同步任務,按照順序一步一步執行 
  7. */ 

3.2、同步和異步

  1. console.log(1); 
  2. setTimeout(function() { 
  3.     console.log(2); 
  4. },1000) 
  5. console.log(3); 
  6. /* 
  7.     執行結果:1、3、2 
  8.     同步任務,按照順序一步一步執行 
  9.     異步任務,放入消息隊列中,等待同步任務執行結束,讀取消息隊列執行 
  10. */ 

3.3、異步任務進一步分析

  1. console.log(1); 
  2. setTimeout(function() { 
  3.     console.log(2); 
  4. },1000) 
  5. setTimeout(function() { 
  6.     console.log(3); 
  7. },0) 
  8. console.log(4); 
  9. /* 
  10.     猜測是:1、4、2、3   但實際上是:1、4、3、2 
  11.     分析: 
  12.         同步任務,按照順序一步一步執行 
  13.         異步任務,當讀取到異步任務的時候,將異步任務放置到Event table(事件表格) 
  14. 中,當滿足某種條件或者說指定事情完成了(這里的是時間分別是達到了0ms和1000ms)當指定 
  15. 事件完成了才從Event table中注冊到Event Queue(事件隊列),當同步事件完成了,便從 
  16. Event Queue中讀取事件執行。(因為3的事情先完成了,所以先從Event table中注冊到 
  17. Event Queue中,所以先執行的是3而不是在前面的2) 
  18. */ 

3.4、宏任務和微任務

  1. console.log(1); 
  2. setTimeout(function() { 
  3.     console.log(2) 
  4. },1000); 
  5. new Promise(function(resolve) { 
  6.     console.log(3); 
  7.     resolve(); 
  8. ).then(function() { 
  9.     console.log(4) 
  10. }); 
  11. console.log(5); 
  12. /* 
  13.     以同步異步的方式來判斷的結果應該是:1、3、5、2、4 
  14.     但是事實上結果是:1、3、5、4、2 
  15.     為什么是這樣呢?因為以同步異步的方式來解釋執行機制是不準確的,更加準確的方式是宏任務和微任務: 
  16.     因此執行機制便為:執行宏任務 ===> 執行微任務 ===> 執行另一個宏任務 ===> 不斷循環 
  17.         即:在一個事件循環中,執行第一個宏任務,宏任務執行結束,執行當前事件循環中的微任務, 
  18. 執行完畢之后進入下一個事件循環中,或者說執行下一個宏任務 
  19. */ 

3.5、是否徹底理解JavaScript執行機制實例

  1. console.log('1'); 
  2. setTimeout(function() { 
  3.     console.log('2'); 
  4.     process.nextTick(function() { 
  5.         console.log('3'); 
  6.     }) 
  7.     new Promise(function(resolve) { 
  8.         console.log('4'); 
  9.         resolve(); 
  10.     }).then(function() { 
  11.         console.log('5'
  12.     }) 
  13. }) 
  14. process.nextTick(function() { 
  15.     console.log('6'); 
  16. }) 
  17. new Promise(function(resolve) { 
  18.     console.log('7'); 
  19.     resolve(); 
  20. }).then(function() { 
  21.     console.log('8'
  22. }) 
  23. setTimeout(function() { 
  24.     console.log('9'); 
  25.     process.nextTick(function() { 
  26.         console.log('10'); 
  27.     }) 
  28.     new Promise(function(resolve) { 
  29.         console.log('11'); 
  30.         resolve(); 
  31.     }).then(function() { 
  32.         console.log('12'
  33.     }) 
  34. }) 
  35. /* 
  36. 1、 第一輪事件循環流程分析如下: 
  37.     整體script作為第一個宏任務進入主線程,遇到console.log,輸出1。 
  38.     遇到setTimeout,其回調函數被分發到宏任務Event Queue中。我們暫且記為setTimeout1。 
  39.     遇到process.nextTick(),其回調函數被分發到微任務Event Queue中。我們記為process1。 
  40.     遇到Promise,new Promise直接執行,輸出7。then被分發到微任務Event Queue中。我們記為then1。 
  41.     又遇到了setTimeout,其回調函數被分發到宏任務Event Queue中,我們記為setTimeout2。 
  42.     宏任務Event Queue   微任務Event Queue 
  43.     setTimeout1         process1 
  44.     setTimeout2         then1 
  45.     上表是第一輪事件循環宏任務結束時各Event Queue的情況,此時已經輸出了1和7。 
  46.     我們發現了process1和then1兩個微任務。 
  47.     執行process1,輸出6。 
  48.     執行then1,輸出8。 
  49.     好了,第一輪事件循環正式結束,這一輪的結果是輸出1,7,6,8。 
  50. 2、 那么第二輪時間循環從setTimeout1宏任務開始: 
  51.     首先輸出2。接下來遇到了process.nextTick(),同樣將其分發到微任務Event Queue中, 
  52. 記為process2。new Promise立即執行輸出4,then也分發到微任務Event Queue中,記為then2。 
  53.     宏任務Event Queue     微任務Event Queue 
  54.     setTimeout2           process2 
  55.                           then2 
  56.     第二輪事件循環宏任務結束,我們發現有process2和then2兩個微任務可以執行。 
  57.         輸出3。 
  58.         輸出5。 
  59.         第二輪事件循環結束,第二輪輸出2,4,3,5。 
  60. 3、 第三輪事件循環開始,此時只剩setTimeout2了,執行。 
  61.         直接輸出9。 
  62.         將process.nextTick()分發到微任務Event Queue中。記為process3。 
  63.         直接執行new Promise,輸出11。 
  64.         將then分發到微任務Event Queue中,記為then3。 
  65.     宏任務Event Queue     微任務Event Queue 
  66.                             process3 
  67.                             then3      
  68.     第三輪事件循環宏任務執行結束,執行兩個微任務process3和then3。 
  69.         輸出10。 
  70.         輸出12。 
  71.         第三輪事件循環結束,第三輪輸出9,11,10,12。 
  72.     整段代碼,共進行了三次事件循環,完整的輸出為1,7,6,8,2,4,3,5,9,11,10,12。 
  73. */ 

總結

javascript是一門單線程語言;

Event Loop是javascript的執行機制;

客戶端也是要學習前端語言的,以后我們會講解一些前端的知識點

本文轉載自微信公眾號「Android開發編程」

 

責任編輯:姜華 來源: Android開發編程
相關推薦

2021-09-01 06:48:16

AndroidGlide緩存

2021-09-26 05:06:46

JS垃圾內存

2021-09-11 07:32:15

Java線程線程池

2021-08-17 13:41:11

AndroidView事件

2021-09-09 06:55:43

AndroidViewDragHel原理

2021-09-04 07:29:57

Android

2021-09-07 06:40:25

AndroidLiveData原理

2021-08-09 20:29:27

Android沉浸式狀態欄

2011-06-23 14:05:32

Qt 事件機制

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-08-12 16:28:10

AndroidHandleLooper

2021-08-05 20:39:34

AndroidKotlinStandard.kt

2021-09-14 07:06:12

Android磁盤緩存

2021-09-18 06:56:01

JavaCAS機制

2021-03-23 07:56:54

JS基礎同步異步編程EventLoop底層

2015-11-20 11:20:54

js開發

2021-09-03 07:27:38

AndroidGlide管理

2021-08-10 20:41:33

AndroidApp流程

2021-10-24 06:50:52

AndroidClassLoaderJava

2021-12-20 00:03:38

Webpack運行機制
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99视频免费在线观看 | 色久电影 | 成年人视频在线免费观看 | 日韩欧美视频网站 | 中文av电影 | 国产日产欧产精品精品推荐蛮挑 | 一级毛片黄片 | 久久免费精品视频 | 国产成人免费视频网站高清观看视频 | 日韩精品无码一区二区三区 | 久久香蕉网 | 中文字幕av在线播放 | 精品国产乱码久久久久久丨区2区 | 欧美国产亚洲一区二区 | 久久亚洲欧美日韩精品专区 | 日韩中文字幕在线视频观看 | 99综合网| 操久久久| 成人a在线 | 亚洲精品久久久久久久久久吃药 | 国产亚洲一区二区精品 | 91精品国产91久久久久久丝袜 | 国产黄色麻豆视频 | 99热精品久久 | 久久久久久久久久性 | 免费成人高清在线视频 | 免费观看一级特黄欧美大片 | 国产精彩视频 | 免费国产视频 | 免费黄色在线 | 国产精品国产精品国产专区不卡 | eeuss国产一区二区三区四区 | 日韩欧美国产成人一区二区 | 久热9| 91久久久精品国产一区二区蜜臀 | 91精品国产综合久久婷婷香蕉 | 久久精品久久久久久 | 日韩欧美专区 | 97在线播放 | 狠狠干综合视频 | 一区二区免费 |