Javascript : Event Queue & Event Loop

更新於 發佈於 閱讀時間約 7 分鐘

前言

這是第一次寫技術文章,但其實應該也只能說是蒐集很多資料並學習如何透過自己的話解釋的內容,並不能像其他大神可能分享一些很酷的技術,目標就單純是為了完成最後一週的作業(如下)。
setTimeout(function(){console.log('delay 0 sec')}, 0)
console.log('Hello!')
透過兩天左右的閱讀資料讓自己對JS在同步與非同步有更多概念,由於有許多專有名詞,因此會先針對各專有名詞作介紹,再敘述自己的看法,最後提供這次參考的網路資源

走入非同步之前

執行環境(Execution Context)
Javascript被執行的地方,在Chrome裡,就是由V8 Engine提供此環境,任何程式碼被執行與讀取的地方都是執行環境,其中又可分為下列三種類型:
  • 全域執行環境 : 預設的執行環境,也就是一開始載入JS檔案的執行環境就是全域執行環境,不在任何函式裡面的程式碼就是在全域執行環境,其功用除了創造全域變數,還會進行記憶體的指派。
  • 函式執行環境 : 就如字面上的意思,即函式被呼叫執行的環境,此執行環境可存在很多個,須注意的是其並不會產生全域物件。
  • eval函式執行環境 : eval對開發者來說是非常方便的函式,可以透過字串方式執行JS,需注意的是如透過EVAL綁定的資料未經過適當編碼與驗證,可能造成注入攻擊的產生,因此現在也較不被推薦使用,甚至在CSP(Content Security Policy,可看成Server回送給Cliet端的Http header裡面的一種安全規範)裡面已經被預設為禁止使用。
執行環境堆疊 (Execution stack)
上面提到函式執行環境可能有很多個,每一個函式被呼叫就會產生一個與之對應的執行環境,此時會透過「堆疊」這種資料結構來儲存函式執行環境,為一種「後進先出」的資料結構。
單線程 (Single-Thread)
一次只能做一件事情,如果有很多事情就會進行排隊,再逐一執行。
非同步(Asynchronous)
即為同一時間可以處理不只一件事情(註: 其他事情亦非同時進行),這在串接第三方API教材的時候就有用到,利用Ajax可以讓瀏覽器向server送出請求時,不需要等待結果仍然可以處裡其他事情,待之後收到response之後,新的內容可以隨時更新至網頁,這也是為什麼瀏覽Facebook、Gmail的時候不需要看到網頁一直重新整理。
Javascript Runtime Environment (JRE)
JRE即為Javascript執行的環境,最常使用的runtiime就是瀏覽器。我們在宣告函數時,使用到的let、const、function、if else,這些都是Javascript的一部分,但其實之前常常使用到的DOM、console.log、這些其實都不是Javascript,而是瀏覽器這個runtime開放給 Javascript 的 API。也就是說不同的runtime會提供不同的東西,例如瀏覽器的DOM就不能再Node.js執行。

研究分享

Javascript是一個同步的程式語言,代表同一時間只做一件事情,也就是一次只跑一段程式碼。但想想如果我們在讀取Facebook網頁,JS除了要渲染畫面還要透過Http請求跟後端拿資料,但如果文章資料很多的時候,在取得所有資料前就都會無法執行其他任務,造成Blocking的現象,因此JS其實也是有非同步執行的能力,讓使用者瀏覽網頁更為順暢。至於如何處理「同步」與「非同步」的動作呢,就要透過我們今天的主角 —Event Queue、 Event Loop。
上面的名詞解釋曾提到DOM其實不算Javascript語言,而是瀏覽器提供的API,讓我們使用者可以在開發時直接使用,其較常使用的API有操作DOM節點的API — document.querySelector、計時的API — setTimeout、 AJAX相關 — XMLHttpRequest。這些由runtime提供的API,不會影響主執行環境的運行,讓網頁可以同時做很多事情(非同步),而這些非同步的行為要如何進行排序呢,即透過Event Queue。Event Queue專門用來執行非同步的函式,等整個主執行環境運行結束以後,才開始依序執行事件儲列裡面的函式,屬於「先進先出」的資料結構
setTimeout(function(){console.log('delay 0 sec')}, 0) 
console.log('Hello!')
因此上述程式碼可看成,Javacript 引擎執行到瀏覽器提供的setTimeout函式時並不會真的停下來,過0秒馬上執行console.log('delay 0 sec'),是在過0秒之後將此函數放到Event Queue,這就像一個待辦清單,裡面的程式不會馬上執行,要所有的全域執行環境與函式執行環境結束後,才會開始執行Event Queue的內容。那要如何知道主環境都已經執行完程式了呢,就是透過Event loop。Event loop可以看成一個無時無刻都在執行的程式,會不斷監聽程式是否全部執行完成,如果環境堆疊是空的,就會去檢查Event Queue是不是有函式待執行,並將Queue的函式移到Stack執行這些「待辦清單」

參考資源

  1. ALPHA Camp教材
  2. [筆記] 理解 JavaScript 中的事件循環、堆疊、佇列和併發模式(Learn event loop, stack, queue, and concurrency mode of JavaScript in depth) ~ PJCHENder<br>那些沒告訴你的小細節
  3. 從「為什麼不能用這個函式」談執行環境(runtime) - Huli
  4. JavaScript 原力覺醒 - 成為絕地武士之路 :: 第 11 屆 iThome 鐵人賽
  5. Understanding Event Loop, Call Stack, Event & Job Queue in Javascript | by Rahul Sagore | Medium
  6. 所以說event loop到底是什麼玩意兒?| Philip Roberts | JSConf EU - YouTube
avatar-img
2會員
15內容數
紀錄轉職路上的點點滴滴
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Blockcyber的沙龍 的其他內容
OBJECTIVE 除了這些技術與見識的增加,與先前學習較大的差異,會強迫自己每週撰寫ORID學習筆記,並針對每週的作業,新增至少一個教材沒有提到的功能,訓練自己查資料並內化的能力。 REFLECTIVE INTERPRETIVE DECISIONAL
Objective 這週為自己設定為禮拜六完成所有課程,同時為兩個小作品「社群名單」、「電影清單」增加至少一個教材要求以外的小功能。 Reflective Interpretive S3 - A14 : 電影清單加碼功能 (codepen.io) Decisional
電影清單:前端體驗綜合實作 Objective Reflective Interpretive Decisional
Objective 因後面有幾個周末無法全空下時間學習,最近又因為專案開始進行常常會加班,為使課程可於期限內完成,為自己設定的目標就是在7/18學期2-2開始前至少完成一周的作業。現在看來至少是完成了最低的標準,並提前開始下週進度。 Reflective Interpretive
為什麼回來了? 重新開始 目前的規劃
OBJECTIVE 除了這些技術與見識的增加,與先前學習較大的差異,會強迫自己每週撰寫ORID學習筆記,並針對每週的作業,新增至少一個教材沒有提到的功能,訓練自己查資料並內化的能力。 REFLECTIVE INTERPRETIVE DECISIONAL
Objective 這週為自己設定為禮拜六完成所有課程,同時為兩個小作品「社群名單」、「電影清單」增加至少一個教材要求以外的小功能。 Reflective Interpretive S3 - A14 : 電影清單加碼功能 (codepen.io) Decisional
電影清單:前端體驗綜合實作 Objective Reflective Interpretive Decisional
Objective 因後面有幾個周末無法全空下時間學習,最近又因為專案開始進行常常會加班,為使課程可於期限內完成,為自己設定的目標就是在7/18學期2-2開始前至少完成一周的作業。現在看來至少是完成了最低的標準,並提前開始下週進度。 Reflective Interpretive
為什麼回來了? 重新開始 目前的規劃
你可能也想看
Google News 追蹤
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
本章節主要介紹了JavaScript中的流程控制,包括條件語句(如if、else if、else和三元運算子)和循環結構(如for迴圈、while迴圈等)。同時,也提供了如何使用break、continue和label來控制迴圈的執行。
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
Thumbnail
本章目的是為讀者提供有關如何設置JavaScript開發環境的知識,包括在瀏覽器、Node.js和各種編輯器和IDE中編寫和運行JavaScript的信息。此外,本章還介紹了如何架設本地開發伺服器以模擬實際的網頁環境。這些知識對於希望開發前端應用或後端服務的JavaScript開發者來說都是必要的。
※ 非同步概念總複習 為什麼要使用 Promise? 在 JavaScript 開發中,處理非同步操作是常見需求,涉及如文件讀寫、數據庫查詢或網路請求等耗時任務。傳統的回調方式可能導致代碼結構混亂,稱為「回調地獄」,難以維護和理解。 Promise 是解決這問題的方法。它是一個物件(objec
什麼是 Promise.all? 在有多個 Promise 的時候,使用 Promise.all 可以確保「所有的 Promise 都執行完以後,才進入 then」。 Promise.all 語法結構: Promise.all 接受的參數是陣列形式。 什麼時候要使用 Promise.all?
※ Promise基本介紹 什麼是 Promise? Promise 是 JavaScript 的一個構造函式,用於創建表示非同步操作的物件實例。使用 new Promise() 時,你會創建一個包含非同步操作的實例,這個實例可以透過其繼承的方法如 then(), catch(), 和 fina
※ 同步概念: 單純地「由上而下」執行程式碼,而且一次只執行一件事,也就是「按順序執行,一個動作結束才能切換到下一個」。缺點是你需要「等待」事情執行完畢,才能繼續往下走。 ※ 非同步概念: 盡可能讓主要的執行程序不需要停下來等待,若遇到要等待的事情,就發起一個「非同步處理」,讓主程序繼續執行,
※ 函式基礎介紹: ※ JavaScript 特殊的函式特性: 函式可以當成值來傳遞 (可以放進變數或放進物件) 函式可以當成函式的參數 callback - 在特定事件中觸發函式 (非同步特性) ※ 函式的基本寫法: ※ 調用 (invoke) 函式: "調用" 意指呼叫或執行
前言: 一直想要把自己的學習筆記整理整理,至少在寫下筆記的時候,也能釐清觀念。 結果拖延到現在,終於要提筆了,不知道能堅持多久(???)。
※ 迴圈(for loop)介紹: 迴圈的用途是重複執行程式碼,只要條件滿足,就會執行特定的動作。 for (let i = 0; i < 10; i = i + 1) { console.log(i); } 說明: for:對於。 let:因為迭代器的數值會一直改變所以要用let
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
本章節主要介紹了JavaScript中的流程控制,包括條件語句(如if、else if、else和三元運算子)和循環結構(如for迴圈、while迴圈等)。同時,也提供了如何使用break、continue和label來控制迴圈的執行。
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
Thumbnail
本章目的是為讀者提供有關如何設置JavaScript開發環境的知識,包括在瀏覽器、Node.js和各種編輯器和IDE中編寫和運行JavaScript的信息。此外,本章還介紹了如何架設本地開發伺服器以模擬實際的網頁環境。這些知識對於希望開發前端應用或後端服務的JavaScript開發者來說都是必要的。
※ 非同步概念總複習 為什麼要使用 Promise? 在 JavaScript 開發中,處理非同步操作是常見需求,涉及如文件讀寫、數據庫查詢或網路請求等耗時任務。傳統的回調方式可能導致代碼結構混亂,稱為「回調地獄」,難以維護和理解。 Promise 是解決這問題的方法。它是一個物件(objec
什麼是 Promise.all? 在有多個 Promise 的時候,使用 Promise.all 可以確保「所有的 Promise 都執行完以後,才進入 then」。 Promise.all 語法結構: Promise.all 接受的參數是陣列形式。 什麼時候要使用 Promise.all?
※ Promise基本介紹 什麼是 Promise? Promise 是 JavaScript 的一個構造函式,用於創建表示非同步操作的物件實例。使用 new Promise() 時,你會創建一個包含非同步操作的實例,這個實例可以透過其繼承的方法如 then(), catch(), 和 fina
※ 同步概念: 單純地「由上而下」執行程式碼,而且一次只執行一件事,也就是「按順序執行,一個動作結束才能切換到下一個」。缺點是你需要「等待」事情執行完畢,才能繼續往下走。 ※ 非同步概念: 盡可能讓主要的執行程序不需要停下來等待,若遇到要等待的事情,就發起一個「非同步處理」,讓主程序繼續執行,
※ 函式基礎介紹: ※ JavaScript 特殊的函式特性: 函式可以當成值來傳遞 (可以放進變數或放進物件) 函式可以當成函式的參數 callback - 在特定事件中觸發函式 (非同步特性) ※ 函式的基本寫法: ※ 調用 (invoke) 函式: "調用" 意指呼叫或執行
前言: 一直想要把自己的學習筆記整理整理,至少在寫下筆記的時候,也能釐清觀念。 結果拖延到現在,終於要提筆了,不知道能堅持多久(???)。
※ 迴圈(for loop)介紹: 迴圈的用途是重複執行程式碼,只要條件滿足,就會執行特定的動作。 for (let i = 0; i < 10; i = i + 1) { console.log(i); } 說明: for:對於。 let:因為迭代器的數值會一直改變所以要用let