中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

幼教網站建設分析今日新聞國際最新消息

幼教網站建設分析,今日新聞國際最新消息,網站建設平臺網站設計,wordpress 鼠標點擊大廠面試題分享 面試題庫后端面試題庫 (面試必備) 推薦:★★★★★地址:前端面試題庫一、異步執(zhí)行原理1. 單線程的JavaScript我們知道,JavaScript是一種單線程語言,它主要用來與用戶互動,以及操…

大廠面試題分享 面試題庫

后端面試題庫 (面試必備) 推薦:★★★★★

地址:前端面試題庫

一、異步執(zhí)行原理


1. 單線程的JavaScript

我們知道,JavaScript是一種單線程語言,它主要用來與用戶互動,以及操作DOM。

JavaScript 有同步和異步的概念,這就解決了代碼阻塞的問題:

  • 同步:如果在一個函數返回的時候,調用者就能夠得到預期結果,那么這個函數就是同步的

  • 異步:如果在函數返回的時候,調用者還不能夠得到預期結果,而是需要在將來通過一定的手段得到,那么這個函數就是異步的。

那單線程有什么影響呢?

  • 在 JS 運行的時候可能會阻止 UI 渲染,這說明了兩個線程是互斥的。這是因為 JS 可以修改 DOM,如果在 JS 執(zhí)行的時候 UI 線程還在工作,就可能導致不能安全的渲染 UI。

  • 得益于 JS 是單線程運行的,可以達到節(jié)省內存,節(jié)約上下文切換時間的好處。

2. 多線程的瀏覽器

JS 是單線程的,在同一個時間只能做一件事情,那為什么瀏覽器可以同時執(zhí)行異步任務呢?

這是因為瀏覽器是多線程的,當 JS 需要執(zhí)行異步任務時,瀏覽器會另外啟動一個線程去執(zhí)行該任務。也就是說,JavaScript是單線程指的是執(zhí)行JavaScript代碼的線程只有一個,是瀏覽器提供的JavaScript引擎線程(主線程)。除此之外,瀏覽器中還有定時器線程、 HTTP 請求線程等線程,這些線程主要不是來執(zhí)行 JS 代碼的。

比如主線程中需要發(fā)送數據請求,就會把這個任務交給異步 HTTP 請求線程去執(zhí)行,等請求數據返回之后,再將 callback 里需要執(zhí)行的 JS 回調交給 JS 引擎線程去執(zhí)行。也就是說,瀏覽器才是真正執(zhí)行發(fā)送請求這個任務的角色,而 JS 只是負責執(zhí)行最后的回調處理。所以這里的異步不是 JS 自身實現的,而是瀏覽器為其提供的能力。

下圖是Chrome瀏覽器的架構圖:

可以看到,Chrome不僅擁有多個進程,還有多個線程。以渲染進程為例,就包含GUI渲染線程、JS引擎線程、事件觸發(fā)線程、定時器觸發(fā)線程、異步HTTP請求線程。這些線程為 JS 在瀏覽器中完成異步任務提供了基礎。

二、瀏覽器的事件循環(huán)


JavaScript的任務分為同步異步

  • 同步任務: 在主線程上排隊執(zhí)行的任務,只有一個任務執(zhí)行完畢,才能執(zhí)行下一個任務,

  • 異步任務: 不進入主線程,而是放在任務隊列中,若有多個異步任務則需要在任務隊列中排隊等待,任務隊列類似于緩沖區(qū),任務下一步會被移到執(zhí)行棧然后主線程執(zhí)行調用棧的任務。

上面提到了任務隊列和執(zhí)行棧,下面就先來看看這兩個概念:

1. 執(zhí)行棧與任務隊列

1)執(zhí)行棧:它是一個存儲函數調用的棧結構,遵循先進后出的原則。它主要負責跟蹤所有要執(zhí)行的代碼。每當一個函數執(zhí)行完成時,就會從堆棧中彈出(pop)該執(zhí)行完成函數;如果有代碼需要進去執(zhí)行的話,就進行 push 操作。以下圖為例:

當執(zhí)行這段代碼時,首先會執(zhí)行一個 main 函數,然后執(zhí)行我們的代碼。根據先進后出的原則,后執(zhí)行的函數會先彈出棧,在圖中也可以發(fā)現,foo 函數后執(zhí)行,當執(zhí)行完畢后就從棧中彈出了。

JavaScript在按順序執(zhí)行執(zhí)行棧中的方法時,每次執(zhí)行一個方法,都會為它生成獨有的執(zhí)行環(huán)境(上下文),當這個方法執(zhí)行完成后,就會銷毀當前的執(zhí)行環(huán)境,并從棧中彈出此方法,然后繼續(xù)執(zhí)行下一個方法。

2)任務隊列: 它使用到的是數據結構中的隊列結構,用來保存異步任務,遵循先進先出的原則。它主要負責將新的任務發(fā)送到隊列中進行處理。

JavaScript在執(zhí)行代碼時,會將同步的代碼按照順序排在執(zhí)行棧中,然后依次執(zhí)行里面的函數。當遇到異步任務時,就將其放入任務隊列中,等待當前執(zhí)行棧所有同步代碼執(zhí)行完成之后,就會從異步任務隊列中取出已完成的異步任務的回調并將其放入執(zhí)行棧中繼續(xù)執(zhí)行,如此循環(huán)往復,直到執(zhí)行完所有任務。

JavaScript任務的執(zhí)行順序如下:

在事件驅動的模式下,至少包含了一個執(zhí)行循環(huán)來檢測任務隊列中是否有新任務。通過不斷循環(huán),去取出異步任務的回調來執(zhí)行,這個過程就是事件循環(huán),每一次循環(huán)就是一個事件周期。

2. 宏任務和微任務

任務隊列其實不止一種,根據任務種類的不同,可以分為微任務(micro task)隊列宏任務(macro task)隊列。常見的任務如下:

  • 宏任務: script( 整體代碼)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 環(huán)境)

  • 微任務: Promise、MutaionObserver、process.nextTick(Node.js 環(huán)境);

任務隊列執(zhí)行順序如下:

可以看到,Eventloop 在處理宏任務和微任務的邏輯時的執(zhí)行情況如下:

  1. JavaScript 引擎首先從宏任務隊列中取出第一個任務

  1. 執(zhí)行完畢后,再將微任務中的所有任務取出,按照順序分別全部執(zhí)行,如果在這一步過程中產生新的微任務,也需要執(zhí)行(在執(zhí)行微任務過程中產生的新的微任務并不會推遲到下一個循環(huán)中執(zhí)行,而是在當前的循環(huán)中繼續(xù)執(zhí)行)

  1. 然后再從宏任務隊列中取下一個,執(zhí)行完畢后,再次將 microtask queue 中的全部取出,循環(huán)往復,直到兩個 queue 中的任務都取完。

也是就是說,一次 Eventloop 循環(huán)會處理一個宏任務和所有這次循環(huán)中產生的微任務。

下面通過一個例子來體會事件循環(huán):

console.log('同步代碼1')setTimeout(() => {console.log('setTimeout')
}, 0)newPromise((resolve) => {console.log('同步代碼2')resolve()
}).then(() => {console.log('promise.then')
})console.log('同步代碼3')
復制代碼

代碼輸出結果如下:

"同步代碼1""同步代碼2""同步代碼3""promise.then""setTimeout"復制代碼

那這段代碼執(zhí)行過程是怎么的呢?

  1. 遇到第一個console,它是同步代碼,加入執(zhí)行棧,執(zhí)行并出棧,打印 "同步代碼1"

  1. 遇到setTimeout,它是一個宏任務,加入宏任務隊列

  1. 遇到new Promise 中的console,為同步代碼,加入執(zhí)行棧,執(zhí)行并出棧,打印 "同步代碼2"

  1. 遇到Promise then,它是一個微任務,加入微任務隊列

  1. 遇到第三個console,它是同步代碼,加入執(zhí)行棧,執(zhí)行并出棧,打印 "同步代碼3"

  1. 此時執(zhí)行棧為空,去執(zhí)行微任務隊列中所有任務,打印 "promise.then"

  1. 執(zhí)行完微任務隊列中的任務,就去執(zhí)行宏任務隊列中的一個任務,打印 "setTimeout"

從上面的宏任務和微任務的工作流程中,可以得出以下結論:

  • 微任務和宏任務是綁定的,每個宏任務在執(zhí)行時,會創(chuàng)建自己的微任務隊列。

  • 微任務的執(zhí)行時長會影響當前宏任務的時長。比如一個宏任務在執(zhí)行過程中,產生了 10 個微任務,執(zhí)行每個微任務的時間是 10ms,那么執(zhí)行這 10 個微任務的時間就是 100ms,也可以說這 10 個微任務讓宏任務的執(zhí)行時間延長了 100ms。

  • 在一個宏任務中,分別創(chuàng)建一個用于回調的宏任務和微任務,無論什么情況下,微任務都早于宏任務執(zhí)行(優(yōu)先級更高)。

那么問題來了,為什么要將任務隊列分為微任務和宏任務呢,他們之間的本質區(qū)別是什么呢?

JavaScript在遇到異步任務時,會將此任務交給其他線程來執(zhí)行(比如遇到setTimeout任務,會交給定時器觸發(fā)線程去執(zhí)行,待計時結束,就會將定時器回調任務放入任務隊列等待主線程來取出執(zhí)行),主線程會繼續(xù)執(zhí)行后面的同步任務。

對于微任務,比如promise.then,當執(zhí)行promise.then時,瀏覽器引擎不會將異步任務交給其他瀏覽器的線程去執(zhí)行,而是將任務回調存在一個隊列中,當執(zhí)行棧中的任務執(zhí)行完之后,就去執(zhí)行promise.then所在的微任務隊列。

所以,宏任務和微任務的本質區(qū)別如下:

  • 微任務:不需要特定的異步線程去執(zhí)行,沒有明確的異步任務去執(zhí)行,只有回調

  • 宏任務:需要特定的異步線程去執(zhí)行,有明確的異步任務去執(zhí)行,有回調

三、Node.js的事件循環(huán)


1. 事件循環(huán)的概念

對于Node.js的事件循環(huán),官網的描述:當Node.js啟動時,它會初始化一個事件循環(huán),來處理輸入的腳本,這個腳本可能進行異步API的調用、調度計時器或調用process.nextTick(),然后開始處理事件循環(huán)。

JavaScript和Node.js是基于V8 引擎的,瀏覽器中包含的異步方式在 NodeJS 中也是一樣的。除此之外,Node.js中還有一些其他的異步形式:

  • 文件 I/O:異步加載本地文件。

  • setImmediate():與 setTimeout 設置 0ms 類似,在某些同步任務完成后立馬執(zhí)行。

  • process.nextTick():在某些同步任務完成后立馬執(zhí)行。

  • server.close、socket.on('close',...)等:關閉回調。

這些異步任務的執(zhí)行就需要依靠Node.js的事件循環(huán)機制了。

Node.js 中的 Event Loop 和瀏覽器中的是完全不相同的東西。Node.js使用V8作為js的解析引擎,而I/O處理方面使用了自己設計的libuv,libuv是一個基于事件驅動的跨平臺抽象層,封裝了不同操作系統(tǒng)一些底層特性,對外提供統(tǒng)一的API,事件循環(huán)機制也是它里面的實現的,如下圖所示:

根據上圖,可以看到Node.js的運行機制如下:

  1. V8引擎負責解析JavaScript腳本;

  1. 解析后的代碼,調用Node API;

  1. libuv庫負責Node API的執(zhí)行。它將不同的任務分配給不同的線程,形成一個Event Loop(事件循環(huán)),以異步的方式將任務的執(zhí)行結果返回給V8引擎;

  1. V8引擎將結果返回給用戶;

2. 事件循環(huán)的流程

其中l(wèi)ibuv引擎中的事件循環(huán)分為 6 個階段,它們會按照順序反復運行。每當進入某一個階段的時候,都會從對應的回調隊列中取出函數去執(zhí)行。當隊列為空或者執(zhí)行的回調函數數量到達系統(tǒng)設定的閾值,就會進入下一階段。下面是Eventloop 事件循環(huán)的流程:

整個流程分為六個階段,當這六個階段執(zhí)行完一次之后,才可以算得上執(zhí)行了一次 Eventloop 的循環(huán)過程。下面來看下這六個階段都做了哪些事:

  1. timers 階段:執(zhí)行timer(setTimeout、setInterval)的回調,由 poll 階段控制;

  1. I/O callbacks 階段:主要執(zhí)行系統(tǒng)級別的回調函數,比如 TCP 連接失敗的回調;

  1. idle, prepare 階段:僅Node.js內部使用,可以忽略;

  1. poll 階段:輪詢等待新的鏈接和請求等事件,執(zhí)行 I/O 回調等;

  1. check 階段:執(zhí)行 setImmediate() 的回調;

  1. close callbacks 階段:執(zhí)行關閉請求的回調函數,比如socket.on('close', ...)

注意:上面每個階段都會去執(zhí)行完當前階段的任務隊列,然后繼續(xù)執(zhí)行當前階段的微任務隊列,只有當前階段所有微任務都執(zhí)行完了,才會進入下個階段,這里也是與瀏覽器中邏輯差異較大的地方。

其中,這里面比較重要的就是第四階段:poll,這一階段中,系統(tǒng)主要做兩件事:

  • 回到 timer 階段執(zhí)行回調

  • 執(zhí)行 I/O 回調

在進入該階段時如果沒有設定了 timer 的話,會出現以下情況:

(1)如果 poll 隊列不為空,會遍歷回調隊列并同步執(zhí)行,直到隊列為空或者達到系統(tǒng)限制;

(2)如果 poll 隊列為空時,會出現以下情況:

  • 如果有 setImmediate 回調需要執(zhí)行,poll 階段會停止并且進入到 check 階段執(zhí)行回調;

  • 如果沒有 setImmediate 回調需要執(zhí)行,會等待回調被加入到隊列中并立即執(zhí)行回調,這里同樣會有個超時時間設置防止一直等待下去;

當設定了 timer 且 poll 隊列為空,則會判斷是否有 timer 超時,如果有的就會回到 timer 階段執(zhí)行回調。

這一過程的具體執(zhí)行流程如下圖所示:

3. 宏任務和微任務

Node.js事件循環(huán)的異步隊列也分為兩種:宏任務隊列和微任務隊列。

  • 常見的宏任務:setTimeout、setInterval、setImmediate、script(整體代碼)、 I/O 操作

  • 常見的微任務:process.nextTick、new Promise().then(回調)

4. process.nextTick()

上面提到了process.nextTick(),它是node中新引入的一個任務隊列,它會在上述各個階段結束時,在進入下一個階段之前立即執(zhí)行。

舉個例子:

setTimeout(() => {console.log('timeout')
}, 0);Promise.resolve().then(() => {console.error('promise')
})process.nextTick(() => {console.error('nextTick')
})
復制代碼

輸出結果如下:

nextTick
promise
timeout
復制代碼

可以看到,process.nextTick()是優(yōu)先于promise的回調執(zhí)行。

5. setImmediate 和 setTimeout

上面還提到了setImmediate 和 setTimeout,這兩者很相似,主要區(qū)別在于調用時機的不同:

  • setImmediate:在poll階段完成時執(zhí)行,即check階段;

  • setTimeout:在poll階段為空閑時,且設定時間到達后執(zhí)行,但它在timer階段執(zhí)行;

例如下面的代碼:

setTimeout(() => {console.log('timeout')
}, 0)setImmediate(() => {console.log('setImmediate')
})
復制代碼

輸出結果如下:

timeout
setImmediate
復制代碼

在上面代碼的執(zhí)行過程中,第一輪循環(huán)后,分別將 setTimeout 和 setImmediate 加入了各自階段的任務隊列。第二輪循環(huán)首先進入timers 階段,執(zhí)行定時器隊列回調,然后 pending callbackspoll 階段沒有任務,因此進入check 階段執(zhí)行 setImmediate 回調。所以最后輸出為timeout、setImmediate。

四、Node與瀏覽器事件循環(huán)的差異


Node.js與瀏覽器的 Event Loop 差異如下:

  • Node.js:microtask 在事件循環(huán)的各個階段之間執(zhí)行;

  • 瀏覽器:microtask 在事件循環(huán)的 macrotask 執(zhí)行完之后執(zhí)行;

Nodejs和瀏覽器的事件循環(huán)流程對比如下:

  1. 執(zhí)行全局的 script 代碼(與瀏覽器無差);

  1. 把微任務隊列清空:注意,Node 清空微任務隊列的手法比較特別。在瀏覽器中,我們只有一個微任務隊列需要接受處理;但在 Node 中,有兩類微任務隊列:next-tick 隊列和其它隊列。其中這個 next-tick 隊列,專門用來收斂 process.nextTick 派發(fā)的異步任務。在清空隊列時,優(yōu)先清空 next-tick 隊列中的任務,隨后才會清空其它微任務

  1. 開始執(zhí)行 macro-task(宏任務)。注意,Node 執(zhí)行宏任務的方式與瀏覽器不同:在瀏覽器中,我們每次出隊并執(zhí)行一個宏任務;而在 Node 中,我們每次會嘗試清空當前階段對應宏任務隊列里的所有任務(除非達到系統(tǒng)限制);

  1. 步驟3開始,會進入 3 -> 2 -> 3 -> 2…的循環(huán)。

大廠面試題分享 面試題庫

后端面試題庫 (面試必備) 推薦:★★★★★

地址:前端面試題庫

http://www.risenshineclean.com/news/21374.html

相關文章:

  • 青縣網站建設蘇州seo服務
  • 做網站開發(fā)語言哪里可以建網站
  • 南京網站制作有限公司fifa世界排名最新
  • 外貿做的亞馬遜網站是哪個百度一下知道首頁
  • wordpress 英文改中文seo顧問是什么職業(yè)
  • 中升乙源建設公司網站各大網站域名大全
  • 畢業(yè)設計購物網站怎么做上海網絡推廣團隊
  • 國外花型設計網站2022真實新聞作文400字
  • win7做網站服務器seo的主要分析工具
  • 表白制作網站網站設計公司
  • 重慶網站制作招聘百度營銷
  • 專業(yè)做外貿網站推廣發(fā)帖網站
  • wordpress 純凈版下載地址seo是什么意思如何實現
  • 微網站技術重慶seo排名優(yōu)化
  • 網站如何做優(yōu)化重慶高端seo
  • 企業(yè)建站公司哪里有如何提高網站在百度的排名
  • 政府網站建設問題餐飲營銷方案
  • 網站在線服務模塊怎么做測試杭州網站推廣優(yōu)化
  • 全球最受歡迎的網站推廣平臺哪兒有怎么做
  • 河北網站建設推廣電話購買一個網站域名需要多少錢
  • 鄱陽網站建設多少錢ui設計培訓班哪家好
  • 杭州營銷網站建設公司少兒編程
  • 制作網頁網站哪個好用怎么網絡推廣自己業(yè)務
  • html5動態(tài)網站模板下載武漢seo學徒
  • 觸屏手機網站鄭州百度網站快速優(yōu)化
  • 網站標題能改嗎互聯網廣告管理暫行辦法
  • 做飛機票預訂網站域名查詢入口
  • 重慶整合營銷網站建設什么推廣方式能快速引流
  • 臨沂網站建設哪家公司好關于進一步優(yōu)化落實疫情防控措施
  • 煙草許可證每年做證去那個網站nba籃網最新消息