進程與線程
進程:
程序的一次執行, 它佔有一片獨有的內存空間
可以通過windows任務管理器查看進程
線程:
是進程內的一個獨立執行單元
是程序執行的一個完整流程
是CPU的最小的調度單元
進程與線程
* 一個進程中一般至少有一個運行的線程: 主線程
* 一個進程中也可以同時運行多個線程, 我們會說程序是多線程運行的
* 一個進程內的數據可以供其中的多個線程直接共享
* 多個進程之間的數據是不能直接共享的
瀏覽器運行是單進程還是多進程?
有的是單進程
* firefox
* 老版IE
有的是多進程
* chrome
* 新版IE
如何查看瀏覽器是否是多進程運行的呢?
- 任務管理器==>進程
瀏覽器運行是單線程還是多線程?
- 都是多線程運行的
相關問題
1.何爲多進程與多線程?
多進程運行: 應用程序可以同時啓動多個實例運行
多線程: 在一個進程內, 同時有多個線程運行
2.比較單線程與多線程?
多線程:
優點:
能有效提升CPU的利用率
缺點:
創建多線程開銷
線程間切換開銷
死鎖與狀態同步問題
單線程:
優點:
順序編程簡單易懂
缺點:
效率低
3.JS是單線程還是多線程?
js是單線程運行的
但使用H5中的 Web Workers可以多線程運行
瀏覽器內核
什麼是瀏覽器內核?
支持瀏覽器運行的最核心的程序
不同的瀏覽器可能不太一樣
* Chrome, Safari: webkit
* firefox: Gecko
* IE: Trident
* 360,搜狗等國內瀏覽器: Trident + webkit
內核由很多模塊組成
* html,css文檔解析模塊 : 負責頁面文本的解析
* dom/css模塊 : 負責dom/css在內存中的相關處理
* 佈局和渲染模塊 : 負責頁面的佈局和效果的繪製
* 定時器模塊 : 負責定時器的管理
* 網絡請求模塊 : 負責服務器請求(常規/Ajax)
* 事件響應模塊 : 負責事件的管理
定時器引發的思考
定時器真是定時執行的嗎?
- 定時器並不能保證真正定時執行
- 一般會延遲一丁點(可以接受), 也有可能延遲很長時間(不能接受)
定時器回調函數是在分線程執行的嗎?
- 在主線程執行的, js是單線程的
定時器是如何實現的?
事件循環模型
document.getElementById('btn').onclick = function () {
var start = Date.now()
console.log('啓動定時器前...')
setTimeout(function () {
console.log('定時器執行了', Date.now()-start)
}, 200)
console.log('啓動定時器後...')
}
JS是單線程的
如何證明js執行是單線程的?
- setTimeout()的回調函數是在主線程執行的
- 定時器回調函數只有在運行棧中的代碼全部執行完後纔有可能執行
爲什麼js要用單線程模式, 而不用多線程模式?
- JavaScript的單線程,與它的用途有關。
- 作爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。
- 這決定了它只能是單線程,否則會帶來很複雜的同步問題
代碼的分類:
- 初始化代碼
- 回調代碼
js引擎執行代碼的基本流程
先執行初始化代碼: 包含一些特別的代碼
* 回調函數(異步執行)
* 設置定時器
* 綁定事件監聽
* 發送ajax請求
後面在某個時刻纔會執行回調代碼
事件循環模型
所有代碼分類
初始化執行代碼(同步代碼): 包含綁定dom事件監聽, 設置定時器, 發送ajax請求的代碼
回調執行代碼(異步代碼): 處理回調邏輯
js引擎執行代碼的基本流程:
初始化代碼===>回調代碼
模型的2個重要組成部分:
- 事件(定時器/DOM事件/Ajax)管理模塊
- 回調隊列
模型的運轉流程
- 執行初始化代碼, 將事件回調函數交給對應模塊管理
- 當事件發生時, 管理模塊會將回調函數及其數據添加到回調列隊中
- 只有當初始化代碼執行完後(可能要一定時間), 纔會遍歷讀取回調隊列中的回調函數執行
Web Workers
- H5規範提供了js分線程的實現, 取名爲: Web Workers
- 相關API
- Worker: 構造函數, 加載分線程執行的js文件
- Worker.prototype.onmessage: 用於接收另一個線程的回調函數
- Worker.prototype.postMessage: 向另一個線程發送消息
- 不足
- worker內代碼不能操作DOM(更新UI)
- 不能跨域加載JS
- 不是每個瀏覽器都支持這個新特性
內存溢出與內存泄露
內存溢出
- 一種程序運行出現的錯誤
- 當程序運行需要的內存超過了剩餘的內存時, 就出拋出內存溢出的錯誤
內存泄露
- 佔用的內存沒有及時釋放
- 內存泄露積累多了就容易導致內存溢出
- 常見的內存泄露:
- 意外的全局變量
- 沒有及時清理的計時器或回調函數
- 閉包
// 1. 內存溢出
var obj = {}
for (var i = 0; i < 10000; i++) {
obj[i] = new Array(10000000)
console.log('-----')
}
// 2. 內存泄露
// 意外的全局變量
function fn() {
a = new Array(10000000)
console.log(a)
}
fn()
// 沒有及時清理的計時器或回調函數
var intervalId = setInterval(function () { //啓動循環定時器後不清理
console.log('----')
}, 1000)
// clearInterval(intervalId)
// 閉包
function fn1() {
var a = 4
function fn2() {
console.log(++a)
}
return fn2
}
var f = fn1()
f()
// f = null