摘要:線程機(jī)制與事件機(jī)制一進(jìn)程與線程進(jìn)程程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間。事件響應(yīng)模塊負(fù)責(zé)事件的管理。當(dāng)事件發(fā)生時管理模塊會將回調(diào)函數(shù)及其數(shù)據(jù)添加到回調(diào)列隊(duì)中。但是子線程完全受主線程控制,且不得操作。向另一個線程發(fā)送消息。
JavaScript線程機(jī)制與事件機(jī)制 一、進(jìn)程與線程 進(jìn)程(process)
程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間。
可以通過windows任務(wù)管理器查看進(jìn)程。
線程(thread)是進(jìn)程內(nèi)的一個獨(dú)立執(zhí)行單元。
是程序執(zhí)行的一個完整流程。
是CPU的最小調(diào)度單元。
進(jìn)程與線程圖解 相關(guān)知識應(yīng)用程序必須運(yùn)行在某個進(jìn)程的某個線程上。
一個進(jìn)程中至少有一個運(yùn)行的線程:主線程,進(jìn)程啟動后自動創(chuàng)建。
一個進(jìn)程中也可以同時運(yùn)行多個線程,我們會說程序是多線程運(yùn)行的。
一個進(jìn)程內(nèi)的數(shù)據(jù)可以供其中的多個線程中直接共享。
多個進(jìn)程之間的數(shù)據(jù)是不能直接共享的。
線程池(thread pool):保存多個線程對象的容器,實(shí)現(xiàn)線程對象的反復(fù)利用。
相關(guān)問題(1)何為多進(jìn)程與多線程?
多進(jìn)程運(yùn)行:一個應(yīng)用程序可以同時啟動多個實(shí)例運(yùn)行。
多線程:在一個進(jìn)程內(nèi),同時有多個線程運(yùn)行。
(2)比較單線程與多線程?
多線程
優(yōu)點(diǎn):能有效提升CPU的利用率。
缺點(diǎn):
創(chuàng)建多線程開銷。
線程間切換開銷。
死鎖與狀態(tài)同步問題。
單線程
優(yōu)點(diǎn):順序編程簡單易懂。
缺點(diǎn):效率低。
(3)JS是單線程還是多線程?
JS是單線程運(yùn)行的。
但是使用H5中的 Web Workers可以多線程運(yùn)行。
(4)瀏覽器運(yùn)行是單線程還是多線程?
瀏覽器都是多線程運(yùn)行的。
(5)瀏覽器運(yùn)行是單進(jìn)程還是多進(jìn)程?
有的是單進(jìn)程:
老版Firefox
老版IE
有的是多進(jìn)程:
Chrome
新版Firefox
新版IE
如何查看瀏覽器是否是多進(jìn)程運(yùn)行的呢?
任務(wù)管理器==>進(jìn)程
二、瀏覽器內(nèi)核(1)瀏覽器內(nèi)核是支撐瀏覽器運(yùn)行的最核心的程序。
(2)不同的瀏覽器內(nèi)核不一樣:
Chrome,Safari:webkit
Firefox:Gecko
IE:Trident
360,搜狗等國內(nèi)瀏覽器:Trident+webkit
(3)內(nèi)核由很多模塊組成:
主線程
js引擎模塊:負(fù)責(zé)js程序的編譯與運(yùn)行。
html,css文檔解析模塊:負(fù)責(zé)頁面文本的解析。
DOM/CSS模塊:負(fù)責(zé)DOM/CSS在內(nèi)存中的相關(guān)處理。
布局和渲染模塊:負(fù)責(zé)頁面的布局和效果的繪制(內(nèi)存中的對象)
分線程
定時器模塊:負(fù)責(zé)定時器的管理。
DOM事件響應(yīng)模塊:負(fù)責(zé)事件的管理。
網(wǎng)絡(luò)請求模塊:負(fù)責(zé)服務(wù)器請求(常規(guī)/ajax)。
三、定時器引發(fā)的思考(1)定時器真是定時執(zhí)行的嗎?
定時器并不能保證真正定時執(zhí)行。
一般會延遲一丁點(diǎn)(可以接受), 也有可能延遲很長時間(不能接受)。
document.getElementById("btn").onclick = function () { var start = Date.now() console.log("啟動定時器前...") setTimeout(function () { console.log("定時器執(zhí)行了", Date.now()-start) }, 200) console.log("啟動定時器后...") }
給上面回調(diào)函數(shù)加一個長時間的任務(wù):
document.getElementById("btn").onclick = function () { var start = Date.now() console.log("啟動定時器前...") setTimeout(function () { console.log("定時器執(zhí)行了", Date.now()-start) }, 200) console.log("啟動定時器后...") // 做一個長時間的工作 for (var i = 0; i < 1000000000; i++) {} }
結(jié)果:
同步任務(wù)執(zhí)行完之后才會執(zhí)行異步任務(wù)。
(2)定時器回調(diào)函數(shù)是在分線程執(zhí)行的嗎?
在主線程執(zhí)行的, js是單線程的。
(3)定時器是如何實(shí)現(xiàn)的?
事件循環(huán)模型(后面講)。
四、JS是單線程執(zhí)行的(1)如何證明js執(zhí)行是單線程的?
setTimeout()的回調(diào)函數(shù)是在主線程執(zhí)行的。
定時器回調(diào)函數(shù)只有在運(yùn)行棧中的代碼全部執(zhí)行完后才有可能執(zhí)行。
(2)為什么js要用單線程模式, 而不用多線程模式?
JavaScript的單線程,與它的用途有關(guān)。
作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。
這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題
(3)代碼的分類:
初始化代碼
回調(diào)代碼
(4)js引擎執(zhí)行代碼的基本流程
先執(zhí)行初始化代碼: 包含一些特別的代碼 ,回調(diào)函數(shù)(異步執(zhí)行)
設(shè)置定時器
綁定監(jiān)聽
發(fā)送ajax請求
后面在某個時刻才會執(zhí)行回調(diào)代碼。
五、瀏覽器的事件循環(huán)(輪詢)模型 瀏覽器的事件循環(huán)模型原理圖 相關(guān)重要概念(1)執(zhí)行棧
execution stack
所有的代碼都是在此空間中執(zhí)行的。
(2)瀏覽器內(nèi)核
browser core
js引擎模塊(在主線程處理)
其它模塊(在主/分線程處理)
(3)任務(wù)隊(duì)列(callback queue)
? task queue
(4)消息隊(duì)列(callback queue)
? message queue
(5)事件隊(duì)列(callback queue)
? event queue
(6)事件輪詢
event loop
從任務(wù)隊(duì)列中循環(huán)取出回調(diào)函數(shù)放入執(zhí)行棧中處理(一個接一個)。
(7)事件驅(qū)動模型
? event-driven interaction model
(8)請求響應(yīng)模型
? request-response model
執(zhí)行流程(1)所有代碼分類:
初始化執(zhí)行代碼:包含綁定dom事件監(jiān)聽, 設(shè)置定時器, 發(fā)送ajax請求的代碼。
回調(diào)執(zhí)行代碼:處理回調(diào)邏輯。
(2)js引擎執(zhí)行代碼的基本流程:
初始化代碼===>回調(diào)代碼
(3)模型的2個重要組成部分:
事件管理模塊
回調(diào)隊(duì)列
(4)模型的運(yùn)轉(zhuǎn)流程:
? (a)執(zhí)行初始化代碼, 將事件回調(diào)函數(shù)交給對應(yīng)模塊管理。
? (b)當(dāng)事件發(fā)生時, 管理模塊會將回調(diào)函數(shù)及其數(shù)據(jù)添加到回調(diào)列隊(duì)中。
? (c)只有當(dāng)初始化代碼執(zhí)行完后(可能要一定時間), 才會遍歷讀取回調(diào)隊(duì)列中的回調(diào)函數(shù)執(zhí)行。
六、H5 Web Workers(多線程) 介紹Web Workers 是 HTML5 提供的一個Javascript多線程解決方案。
我們可以將一些大計算量的代碼交由Web Worker運(yùn)行而不凍結(jié)用戶界面。
但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)
使用
相關(guān)API
Worker: 構(gòu)造函數(shù), 加載分線程執(zhí)行的js文件。
Worker.prototype.onmessage: 用于接收另一個線程的回調(diào)函數(shù)。
Worker.prototype.postMessage: 向另一個線程發(fā)送消息。
創(chuàng)建在分線程執(zhí)行的JS文件
var onmessage = function (event){ //不能用函數(shù)聲明 console.log("onMessage()22"); var upper = event.data.toUpperCase();//通過event.data獲得發(fā)送來的數(shù)據(jù) postMessage( upper );//將獲取到的數(shù)據(jù)發(fā)送回主線程 }
在主線程中的JS中發(fā)消息并設(shè)置回調(diào)
//創(chuàng)建一個Worker對象并向它傳遞將在新線程中執(zhí)行的腳本的URL var worker = new Worker("worker.js"); //接收worker傳過來的數(shù)據(jù)函數(shù) worker.onmessage = function (event) { console.log(event.data); }; //向worker發(fā)送數(shù)據(jù) worker.postMessage("hello world");圖解 應(yīng)用練習(xí)
編程實(shí)現(xiàn)斐波那契數(shù)列(Fibonacci sequence)的計算 F(0)=0,F(xiàn)(1)=1,..... F(n)=F(n-1)+F(n-2)
直接在主線程:
var fibonacci =function(n) { return n <2 ? n : fibonacci(n -1) + fibonacci(n -2); }; console.log(fibonacci(48));
使用Web Workers在分線程:
主線程:
var worker = new Worker("worker2.js"); worker.addEventListener("message", function (event) { var timer2 = new Date().getTime(); console.log("結(jié)果:" + event.data, "時間:" + timer2, "用時:" + ( timer2 - timer )); }, false); var timer = new Date().getTime(); console.log("開始計算: ", "時間:" + timer); setTimeout(function () { console.log("定時器函數(shù)在計算數(shù)列時執(zhí)行了", "時間:" + new Date().getTime()); }, 1000); worker.postMessage(40); console.log("我在計算數(shù)列的時候執(zhí)行了", "時間:" + new Date().getTime());
分線程:
var fibonacci =function(n) { return n <2 ? n : fibonacci(n -1) + fibonacci(n -2); }; var onmessage = function(event) { var n = parseInt(event.data, 10); postMessage(fibonacci(n)); };不足
慢。
不能跨域加載JS。
worker內(nèi)代碼不能訪問DOM(更新UI)。
不是每個瀏覽器都支持這個新特性。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105093.html
摘要:的單線程,與它的用途有關(guān)。特點(diǎn)的顯著特點(diǎn)異步機(jī)制事件驅(qū)動。隊(duì)列的讀取輪詢線程,事件的消費(fèi)者,的主角。它將不同的任務(wù)分配給不同的線程,形成一個事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 這兩天跟同事同事討論遇到的一個問題,js中的event loop,引出了chrome與node中運(yùn)行具有setTimeout和Promise的程序時候執(zhí)行結(jié)果不一樣的問題,從而引出了Nodejs的...
摘要:事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。終于執(zhí)行完了,終于從進(jìn)入了主線程執(zhí)行。遇到,立即執(zhí)行。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個微任務(wù)和。事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發(fā)工作...
摘要:事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。最后的最后是一門單線程語言是的執(zhí)行機(jī)制部分內(nèi)容轉(zhuǎn)自 1.單線程 javascript是一門單線程語言 2.javascript事件循環(huán) 同步任務(wù) 異步任務(wù) showImg(https://segmentfault.com/img/bVbufUd?w=1268&h=1062);除了廣義的同步任務(wù)和異步任務(wù),我們對任務(wù)有更精細(xì)的定義...
摘要:關(guān)于這部分有嚴(yán)格的文字定義,但本文的目的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制,所以同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行場所,同步的進(jìn)入主線程,異步的進(jìn)入并注冊函數(shù)。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個微任務(wù)和。 不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發(fā)工作,我們經(jīng)常會遇到這樣的情況:給定的幾行代碼,我們需要知道其輸出內(nèi)容和順序。 因?yàn)閖avascr...
摘要:瀏覽器是多進(jìn)程的詳情看我上篇總結(jié)瀏覽器執(zhí)行機(jī)制的文章深入前端徹底搞懂瀏覽器運(yùn)行機(jī)制瀏覽器每打開一個標(biāo)簽頁,就相當(dāng)于創(chuàng)建了一個獨(dú)立的瀏覽器進(jìn)程。執(zhí)行異步操作事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。 最近看了很多關(guān)于JS運(yùn)行機(jī)制的文章,每篇都獲益匪淺,但各有不同,所以在這里對這幾篇文章里說的很精辟的地方做一個總結(jié),參考文章鏈接見最后。本文博客地址 了解進(jìn)程和線程 進(jìn)程是應(yīng)用...
閱讀 1686·2021-11-17 09:33
閱讀 3547·2021-11-16 11:40
閱讀 3066·2019-08-30 11:23
閱讀 1059·2019-08-29 16:36
閱讀 2477·2019-08-29 13:23
閱讀 1751·2019-08-29 12:59
閱讀 1555·2019-08-29 12:42
閱讀 1992·2019-08-28 18:22