亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JS核心知識點(diǎn)梳理——異步,單線程,運(yùn)行機(jī)制

TANKING / 3338人閱讀

摘要:引言學(xué)習(xí)的時(shí)候,經(jīng)常聽人說,即是異步的,又是單線程的。所以我們說是異步單線程的。參考從瀏覽器多進(jìn)程到單線程,運(yùn)行機(jī)制最全面的一次梳理運(yùn)行機(jī)制詳解再談異步機(jī)制詳解運(yùn)行原理解析并發(fā)模型與事件循環(huán)

引言

學(xué)習(xí)javascipt的時(shí)候,經(jīng)常聽人說,javascipt即是異步的,又是單線程的。究竟什么是異步,什么是單線程?javascript在瀏覽器中的運(yùn)行機(jī)制是怎么樣的?什么是eventloop,task queue?怎么寫異步函數(shù)?相信讀完這篇文章,相信你會對上面問題有一個(gè)全面的認(rèn)識。

全面了解瀏覽器 瀏覽器有許多進(jìn)程:

Browser進(jìn)程:瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào)、主控),只有一個(gè)。

第三方插件進(jìn)程:每種類型的插件對應(yīng)一個(gè)進(jìn)程,僅當(dāng)使用該插件時(shí)才創(chuàng)建

GPU進(jìn)程:最多一個(gè),用于3D繪制等

瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核)(Renderer進(jìn)程,內(nèi)部是多線程的)

在瀏覽器渲染進(jìn)程中有許多線程:

渲染引擎線程:顧名思義,該線程負(fù)責(zé)頁面的渲染

JS引擎線程:負(fù)責(zé)JS的解析和執(zhí)行(主線程)

定時(shí)觸發(fā)器線程:處理定時(shí)事件,比如setTimeout, setInterval

事件觸發(fā)線程:處理DOM事件

異步http請求線程:處理http請求

雖然JavaScript是單線程的(說的是JS引擎線程),可是瀏覽器內(nèi)部不是單線程的。一些I/O操作、定時(shí)器的計(jì)時(shí)和事件監(jiān)聽(click, keydown...)等都是由瀏覽器提供的其他線程來完成的。
主線程和渲染引擎線程互斥,因?yàn)殇秩镜臅r(shí)候主線程可能通過dom操作渲染結(jié)果,所以主線程必須被阻塞

單線程,異步 判斷標(biāo)準(zhǔn)

之前傻傻的分不清楚單線程多線程,同步異步。其實(shí)很簡單

異步的判斷標(biāo)準(zhǔn):是否阻塞,同步阻塞,異步不阻塞。

單線程的判斷標(biāo)準(zhǔn):一次是否只做一件事。

JS引擎一次只做一件事。遇到異步任務(wù)并不會阻塞后面的同步任務(wù)(不等待)。所以我們說JS是異步 單線程的。需要注意的是JS引擎其實(shí)并不提供異步的支持,異步支持主要依賴于運(yùn)行環(huán)境(瀏覽器或Node.js)。

while阻塞實(shí)驗(yàn)
var start = new Date();
    while(new Date() - start < 100000) { // delay 10 sec
        ;
    }

上面代碼在chrome控制臺輸入可以手動阻塞當(dāng)前頁面的js主線程10s。然后我們在當(dāng)前頁面輸入console.log(1),當(dāng)前頁面無反應(yīng),在另外的頁面輸入console.log(1)直接打印
說明瀏覽器每個(gè)頁面都會多帶帶起一個(gè)進(jìn)程,頁面1的主線程被阻塞并不會影響影響頁面2的主線程

執(zhí)行機(jī)制

JS Engine和runtime Environment

之前在Stackoverflow看了一個(gè)答案,感覺還比較靠譜

JavaScript Engine:parse your code and convert it to runnable commands
JavaScript Runtime Environment :provide some objects to javascript so that it can interact with the outside world.
For example, the Chrome Browser and node.js use the same Engine - V8, but their Runtimes are different: in Chrome you have the window, DOM objects etc, while node gives you require, Buffers and processes.

通俗的講,上面這張圖,左邊你可以看成JS引擎,右邊你可以看成JS運(yùn)行環(huán)境

Eventloop

之前已經(jīng)說了,JS在設(shè)計(jì)之初選擇單線程,是以為單線程簡單,可控。

但是單線程存在一個(gè)問題,部分任務(wù)比如Ajax請求數(shù)據(jù),如果設(shè)計(jì)成同步的,后面的任務(wù)將都去等待Ajax請求完,這個(gè)性能是不能接受的。

所以瀏覽器內(nèi)核(?個(gè)人推測,暫時(shí)沒有找到相關(guān)資料)將任務(wù)分為同步任務(wù)和異步任務(wù),所有同步任務(wù)放到主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。所以異步任務(wù)放到其他異步線程上去執(zhí)行。

當(dāng)異步任務(wù)執(zhí)行完以后,相關(guān)回調(diào)函數(shù)會放入到消息隊(duì)列(也有叫callback queue、task queue)中。

主線程同步任務(wù)執(zhí)行完,每個(gè)一段事件會檢查消息隊(duì)列一次,有回調(diào)函數(shù)就會執(zhí)行,如此往復(fù)就成為Eventloop

個(gè)人的理解 :JS引擎是同步的,瀏覽器通過eventloop這種機(jī)制實(shí)現(xiàn)了異步

看一下How JavaScript works 怎么描述這個(gè)過程的

So, for example, when your JavaScript program makes an Ajax request to fetch some data from the server, you set up the “response” code in a function (the “callback”), and the JS Engine tells the hosting environment:
“Hey, I’m going to suspend execution for now, but whenever you finish with that network request, and you have some data, please call this function back.”

The browser is then set up to listen for the response from the network, and when it has something to return to you, it will schedule the callback function to be executed by inserting it into the event loop.

宏任務(wù),微任務(wù)、練習(xí)

面試喜歡考宏任務(wù)(macrotask),微任務(wù)(microtask)。那么我們就來講一講macrotask和microtask是個(gè)啥子

宏任務(wù)又成為task。可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個(gè)task,task1->渲染->task1

microtask,可以理解是在當(dāng)前 task 執(zhí)行結(jié)束后立即執(zhí)行的任務(wù),所以microtask有歸屬性,只在對應(yīng)的task執(zhí)行完后立即執(zhí)行.task1->microtask1->渲染->task2->microtask2->渲染...

macrotask:主代碼塊,setTimeout,setInterval等(可以看到,事件隊(duì)列中的每一個(gè)事件都是一個(gè)macrotask)

microtask:Promise,process.nextTick等

求下面代碼的結(jié)果

console.log("1");
setTimeout(function() { //回調(diào)2
    new Promise(function(resolve) {
        console.log("2");
        resolve();
    }).then(function() {
        console.log("3")
    })
    console.log("4");
},2000)
new Promise(function(resolve) {
    console.log("5");
    resolve();
}).then(function() {
    console.log("6")
})

setTimeout(function() {  //回調(diào)1
    new Promise(function(resolve) {
        console.log("7");
        resolve();
    }).then(function() {
        console.log("8")
    })
      setTimeout(function(){ //回調(diào)3
        console.log("9")
    },2000)
},1000)

//(156) (78) (243) (9)

解析:
task1: 輸出1 5 ----> microtask1 輸出6 --(執(zhí)行??眨?->render---->eventloop
1秒以后 callback queue里面加入回調(diào)1 被eventloop捕獲,同步任務(wù)入棧,異步任務(wù)給settiomeout線程(也就是回調(diào)3的那個(gè)異步任務(wù))
task2: 輸出7 ----> microtask2 輸出8 --(執(zhí)行??眨?->render---->eventloop
2秒以后 callback queue里面加入回調(diào)2 被eventloop捕獲,同步任務(wù)入棧
task3: 輸出2 4 ----> microtask3 輸出3 --(執(zhí)行??眨?->render---->eventloop
3秒以后 callback queue里面加入回調(diào)3 被eventloop捕獲,同步任務(wù)入棧
task4: 輸出9 --(執(zhí)行棧空)-->render---->eventloop...

異步編程 回調(diào)函數(shù)實(shí)現(xiàn)
let fs = require("fs");
fs.readFile("./1.js","utf-8",(err,data)=>{
    //
    fs.readFile("./2.js","utf-8",(err,data)=>{
         //
         fs.readFile("./3.js","utf-8",(err,data)=>{
                //
         })
    })
})

缺點(diǎn)是容易形成回調(diào)地獄,不能return

promise
const fs = require("fs");
const readFile(i) = new Promise(function(){
     fs.readFile(`./${i}.js`,"utf-8",(err,data)=>{
            resolve(data)
         })
})
    readFile(1)
   .then(readFile(2))
   .then(readFile(3))
   .....
async await
async function read(){
 //await后面必須跟一個(gè)promise,
 let a = await readFile("./1.txt");
 console.log(a);
 let b = await readFile("./2.txt");
 console.log(b);
 let c = await readFile("./3.txt");
 console.log(c);
 return "end";
 }
尾聲

以上是我看了多篇文章以后,結(jié)合自己的理解,對javascript異步單線程,以及運(yùn)行機(jī)制做的一個(gè)總結(jié)。如果你感覺哪一部分有點(diǎn)問題,歡迎在評論區(qū)留言。

參考

從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制最全面的一次梳理
JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop
JavaScript異步機(jī)制詳解
JavaScript 運(yùn)行原理解析
What is the difference between JavaScript Engine and JavaScript Runtime Environment
并發(fā)模型與事件循環(huán)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/109828.html

相關(guān)文章

  • 從瀏覽器多進(jìn)程到JS線程,JS運(yùn)行機(jī)制最全面的一次梳理

    摘要:如果看完本文后,還對進(jìn)程線程傻傻分不清,不清楚瀏覽器多進(jìn)程瀏覽器內(nèi)核多線程單線程運(yùn)行機(jī)制的區(qū)別。因此準(zhǔn)備梳理這塊知識點(diǎn),結(jié)合已有的認(rèn)知,基于網(wǎng)上的大量參考資料,從瀏覽器多進(jìn)程到單線程,將引擎的運(yùn)行機(jī)制系統(tǒng)的梳理一遍。 前言 見解有限,如有描述不當(dāng)之處,請幫忙及時(shí)指出,如有錯(cuò)誤,會及時(shí)修正。 ----------超長文+多圖預(yù)警,需要花費(fèi)不少時(shí)間。---------- 如果看完本文后,還...

    wanghui 評論0 收藏0
  • 知識梳理】4.2JS運(yùn)行機(jī)制

    摘要:任務(wù)隊(duì)列分同步任務(wù)異步任務(wù),異步任務(wù)要掛起,同步任務(wù)全部執(zhí)行完再執(zhí)行異步任務(wù)。執(zhí)行棧執(zhí)行的是同步任務(wù)。什么時(shí)候開啟異步任務(wù)和事件的,先注冊函數(shù)體,觸發(fā)時(shí)放入異步任務(wù)隊(duì)列,再執(zhí)行點(diǎn)擊某一按鈕瀏覽器卡死中的。 1.對比同步和異步 使用異步的場景: 定時(shí)任務(wù):setTimeout、setInterval 網(wǎng)絡(luò)請求:ajax請求、動態(tài)加載 事件綁定 //同步 console.log(1...

    cgh1999520 評論0 收藏0
  • JS異步編程之callback

    摘要:而異步則是相反,調(diào)用在發(fā)出之后,這個(gè)調(diào)用就直接返回了,所以沒有返回結(jié)果而是在調(diào)用發(fā)出后,被調(diào)用者通過狀態(tài)通知來通知調(diào)用者,或通過回調(diào)函數(shù)處理這個(gè)調(diào)用。總結(jié)回調(diào)函數(shù)是異步編程中的基石,但同時(shí)也存在很多問題,不太適合人類自然語言的線性思維習(xí)慣。 為什么 JS 是單線程? 眾所周知,Javascript 語言的執(zhí)行環(huán)境是單線程(single thread)。 所謂單線程,就是指一次只能完成一...

    superw 評論0 收藏0
  • Event Loop

    摘要:引擎線程,也稱為內(nèi)核,負(fù)責(zé)處理腳本程序,例如引擎。異步請求線程,也就是發(fā)出請求后,接收響應(yīng)檢測狀態(tài)變更等都是這個(gè)線程管理的。為了解決這個(gè)問題,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制,且不得操作。 本文主要參閱了以下兩篇文章,對JS的Event Loop運(yùn)行機(jī)制基礎(chǔ)知識進(jìn)行了整理。從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制最全面的一次梳理JavaScript 運(yùn)行機(jī)制詳...

    darkbug 評論0 收藏0
  • Javascript系列之javascript機(jī)制

    摘要:異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)異步任務(wù)從任務(wù)隊(duì)列回到執(zhí)行棧,回調(diào)函數(shù)就會執(zhí)行。事件循環(huán)主線程從任務(wù)隊(duì)列中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為。事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過程。 參考鏈接:這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制https://zhuanlan.zhihu.com/p/...從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制...

    13651657101 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<