日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【转载】浏览器事件循环机制(event loop)

發布時間:2023/11/27 生活经验 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转载】浏览器事件循环机制(event loop) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先,本文轉自https://juejin.im/post/5afbc62151882542af04112d

當我看完菲利普·羅伯茨的 javascript event loop的演講的時候,就對于事件循環很感興趣,于是查閱資料想寫一篇文章總結下,看了一些資料和博客,以及下筆嘗試后,感覺自己水平有限,看到作者的文筆和思路都很好的表達了我想要了解和困惑的東西,遂轉載過來。

JS是單線程的

JS是單線程的,或者說只有一個主線程,也就是它一次只能執行一段代碼。JS中其實是沒有線程概念的,所謂的單線程也只是相對于多線程而言。JS的設計初衷就沒有考慮這些,針對JS這種不具備并行任務處理的特性,我們稱之為“單線程”。

雖然JS運行在瀏覽器中是單線程的,但是瀏覽器是事件驅動的(Event driven),瀏覽器中很多行為是異步(Asynchronized)的,會創建事件并放入執行隊列中。瀏覽器中很多異步行為都是由瀏覽器新開一個線程去完成,一個瀏覽器至少實現三個常駐線程:

  • JS引擎線程
  • GUI渲染線程
  • 事件觸發線程

JS引擎

JavaScript引擎是一個專門處理JavaScript腳本的虛擬機,一般會附帶在網頁瀏覽器之中,比如最出名的就是Chrome瀏覽器的V8引擎,如下圖所示,JS引擎主要有兩個組件構成:

  • 堆-內存分配發生的地方
  • 棧-函數調用時會形一個個棧幀(frame)?

執行棧

每一個函數執行的時候,都會生成新的execution context(執行上下文),執行上下文會包含一些當前函數的參數、局部變量之類的信息,它會被推入棧中, running execution context(正在執行的上下文)始終處于棧的頂部。當函數執行完后,它的執行上下文會從棧彈出。

舉個簡單的例子:
function bar() {
console.log('bar');
}function foo() {
console.log('foo');
bar();
}foo();

?

執行過程中棧的變化:

?

event loop(事件循環)

Wikipedia這樣定義:

"Event Loop是一個程序結構,用于等待和發送消息和事件。(a programming construct that waits for and dispatches events or messages in a program.)"

簡單說,就是在程序中設置兩個線程:一個負責程序本身的運行,稱為"主線程";另一個負責主線程與其他進程(主要是各種I/O操作)的通信,被稱為"Event Loop線程"(可以譯為"消息線程")。

?

事件循環與任務隊列

事件循環可以簡單描述為:

  1. 函數入棧,當Stack中執行到異步任務的時候,就將他丟給WebAPIs,接著執行同步任務,直到Stack為空;
  2. 在此期間WebAPIs完成這個事件,把回調函數放入CallbackQueue中等待;
  3. 當執行棧為空時,Event Loop把Callback Queue中的一個任務放入Stack中,回到第1步。
  • Event Loop是由javascript宿主環境(像瀏覽器)來實現的;
  • WebAPIs是由C++實現的瀏覽器創建的線程,處理諸如DOM事件、http請求、定時器等異步事件;
  • JavaScript 的并發模型基于"事件循環";
  • Callback Queue(Event Queue 或者 Message Queue) 任務隊列,存放異步任務的回調函數

接下來看一個異步函數執行的例子:

var start=new Date();
setTimeout(function cb(){console.log("時間間隔:",new Date()-start+'ms');
},500);
while(new Date()-start<1000){};
  1. main(Script) 函數入棧,start變量開始初始化
  2. setTimeout入棧,出棧,丟給WebAPIs,開始定時500ms;
  3. while循環入棧,開始阻塞1000ms;
  4. 500ms過后,WebAPIs把cb()放入任務隊列,此時while循環還在棧中,cb()等待;
  5. 又過了500ms,while循環執行完畢從棧中彈出,main()彈出,此時棧為空,Event Loop,cb()進入棧,log()進棧,輸出'時間間隔:1003ms',出棧,cb()出棧

宏任務(Macrotasks)和微任務(Microtasks)

其實我們上面所說的都是宏任務(Macrotasks),但是js中還有一種隊列微任務(Microtasks)。

macro-task(Task):一個event loop有一個或者多個task隊列。task任務源非常寬泛,比如ajax的onload,click事件,基本上我們經常綁定的各種事件都是task任務源,還有數據庫操作(IndexedDB ),需要注意的是setTimeout、setInterval、setImmediate也是task任務源。總結來說task任務源:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

micro-task(Job):microtask?隊列和task 隊列有些相似,都是先進先出的隊列,由指定的任務源去提供任務,不同的是一個 event loop里只有一個microtask 隊列。另外microtask執行時機和Macrotasks也有所差異

  • process.nextTick
  • promises
  • Object.observe
  • MutationObserver

那么Macrotasks和Microtasks有什么別區別呢
舉個簡單的例子,假設一個script標簽的代碼如下:

Promise.resolve().then(function promise1 () {console.log('promise1');})
setTimeout(function setTimeout1 (){console.log('setTimeout1')Promise.resolve().then(function  promise2 () {console.log('promise2'); }) }, 0) setTimeout(function setTimeout2 (){ console.log('setTimeout2') }, 0)

運行過程:

script里的代碼被列為一個task,放入task隊列。

循環1:

  • 【task隊列:script ;microtask隊列:】
  1. 從task隊列中取出script任務,推入棧中執行。
  2. promise1列為microtask,setTimeout1列為task,setTimeout2列為task。
  • 【task隊列:setTimeout1 setTimeout2;microtask隊列:promise1】
  1. script任務執行完畢,執行microtask checkpoint,取出microtask隊列的promise1執行。

循環2:

*【task隊列:setTimeout1 setTimeout2;microtask隊列:】 4. 從task隊列中取出setTimeout1,推入棧中執行,將promise2列為microtask。

  • 【task隊列:setTimeout2;microtask隊列:promise2】
  1. 執行microtask checkpoint,取出microtask隊列的promise2執行。

循環3:

  • 【task隊列:setTimeout2;microtask隊列:】
  1. 從task隊列中取出setTimeout2,推入棧中執行。 7.setTimeout2任務執行完畢,執行microtask checkpoint。
  • 【task隊列:;microtask隊列:】

?

?

綜上所說,每次event loop循環執行棧完成后,會繼續執行完相應的microtask任務

event loop中的Update the rendering(更新渲染)

這是event loop中很重要部分,在第7步會進行Update the rendering(更新渲染),規范允許瀏覽器自己選擇是否更新視圖。也就是說可能不是每輪事件循環都去更新視圖,只在有必要的時候才更新視圖。

轉載于:https://www.cnblogs.com/chrissong/p/10582276.html

總結

以上是生活随笔為你收集整理的【转载】浏览器事件循环机制(event loop)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。