1. 程式人生 > >js 運行機制

js 運行機制

最大 註意 結束 一位 執行時間 pos interval 既然 來看

javascript的運行機制

  • 單線程
  • 任務隊列
  • 事件和回調函數
  • 異步IO

javascript最大的特點就是單線程,也就是在同一時間只能做一件事情.那為什麽會是單線程呢?這還要從javascript的用途來看.javascript的主要用途就是與用戶互動以及DOM操作(瀏覽器中),這就決定的了它必須是單線程的,不然會出現很嚴重的問題.比如當有兩個線程同時對一個DOM進行操作的時候,瀏覽器不知道到底以哪個線程為準.既然是單線程的,又怎樣保證性能呢?接下來我們就來看看javascript的運行機制

因為nodejs的出現,js不再只是運行在瀏覽器端,還可以運行在服務端,所有我們就分別從這兩個方面去考慮

瀏覽器端

上面說到js是單線程的,那是不是意味著所有的任務就需要排成一個隊列,每個任務都必須等待上一個任務完成才能繼續下去.如果上一個任務很耗時間,那我們就需要一直等.顯然這是不合理的

在js中I/O操作是很慢的(比如ajax操作就需要從網絡中獲取數據),但是此時CPU卻是非常空閑的.所以這個時候,js會掛起這個I/O操作(我們稱為異步),繼續執行下面的代碼,等到IO操作結束後返回結果,再把掛起的任務繼續執行下去

任務隊列(可以有多個)

  • macrotask
  • microtask

前面我們說js是單線程的,但是在主線程之外,還維持著一個任務隊列.每當js去執行代碼的時候(同步),遇見異步任務的時候,不會等待主線程去執行它,會把這個任務加入任務隊列

,只有任務隊列通知主線程,這個異步隊列可以執行了,該任務才會進入主線程執行,這個過程可以按照如下表述

  • 所有同步操作都是在主線程上操作,形成一個執行棧
  • 主線程之外,還存在一個任務隊列.只要異步任務有了運行結果,就在任務隊列之中放置一個事件
  • 一旦執行棧中所有同步任務執行完畢,系統就會讀取異步隊列,然後對應的事件就會進入執行棧,開始執行.主線程不斷執行這個操作,知道隊列清空

事件循環(只有一個)和回調函數

"任務隊列"是一個事件的隊列(也可以理解成消息的隊列),IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務可以進入"執行棧"了。主線程讀取"任務隊列",就是讀取裏面有哪些事件。

"任務隊列"中的事件,除了IO設備的事件以外,還包括一些用戶產生的事件(比如鼠標點擊、頁面滾動等等).只要指定過回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。

所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。

"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動進入主線程。但是,由於存在後文提到的"定時器"功能,主線程首先要檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。

定時器

除了放置異步任務的事件,"任務隊列"還可以放置定時事件,即指定某些代碼在多少時間之後執行。這叫做"定時器"功能,也就是定時執行的代碼。

定時器功能主要由setTimeout()和setInterval()這兩個函數來完成,它們的內部運行機制完全一樣,區別在於前者指定的代碼是一次性執行,後者則為反復執行

需要註意的是,setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執行棧)執行完,主線程才會去執行它指定的回調函數。要是當前代碼耗時很長,有可能要等很久,所以並沒有辦法保證.



JS中的異步操作:
1、定時器都是異步操作
2、事件綁定都是異步操作
3、AJAX中一般我們都采取異步操作(也可以同步)
4、回調函數可以理解為異步(不是嚴謹的異步操作)

js 運行機制