寫這篇文章呢,也是查閱的很多文章,但是大部分寫的都很簡單,而且概念性的東西都很模糊,於是我就找了一些課程聽了一下,做了一些筆記,在這我就簡單總結一下,方便以後複習~
1. 程序:程式的一次執行, 它佔有一片獨有的記憶體空間 ---- 可以通過windows工作管理員檢視程序;
2. 執行緒: 是程序內的一個獨立執行單元;是程式執行的一個完整流程;CPU的基本排程單位;
3. 程序與執行緒的關係:
* 一個程序中一般至少有一個執行的執行緒: 主執行緒 -- 程序啟動後自動建立;
* 一個程序中也可以同時執行多個執行緒, 我們會說程式是多執行緒執行的;
* 一個程序內的資料可以供其中的多個執行緒直接共用;
* 多個程序之間的資料是不能直接共用的
4. 瀏覽器執行是單程序還是多程序?
* 有的是單程序
* firefox
* 有的是多程序
* chrome
5. 如何檢視瀏覽器是否是多程序執行的呢?
* 工作管理員==>程序
6. 瀏覽器執行是單執行緒還是多執行緒?
* 都是多執行緒執行的
JavaScript語言的一大特點就是單執行緒,也就是說同一時間只能做一件事。
//栗子 console.log(1) console.log(2) console.log(3) //輸出順序 1 2 3
為了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript指令碼建立多個執行緒,但是子執行緒完全受主執行緒控制,且不得操作DOM。所以,這個新標準並沒有改變JavaScript單執行緒的本質。
同步任務: 在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
所有同步任務都在主執行緒上執行,形成一個執行棧(execution context stack)。
非同步任務:在主執行緒外執行的任務;在主執行緒之外還存在一個「任務佇列」(task queue),當非同步任務執行完成後會以回撥函數的方式放入任務佇列中等待,等主執行緒空閒時,主執行緒就會去事件佇列中取出等待的回撥函數放入主執行緒中進行執行。這個過程反覆執行就形成了js的事件迴圈機制(Event Loop)。
//栗子 // 同步 console.log(1) // 非同步 setTimeout(()=>{ console.log(2) },100) // 同步 console.log(3) //輸出順序 1 3 2
如果在JS程式碼執行過程中,某段程式碼執行過久,後面的程式碼遲遲不能執行,產生阻塞(即卡死),會影響使用者體驗。
其實上面我們已經提到了,JS實現非同步時通過 事件迴圈;
我們先理解幾個概念:
當一個JS檔案第一次執行的時候,js引擎會 解析這段程式碼,並將其中的同步程式碼 按照執行順序加入執行棧中,然後從頭開始執行。如果當前執行的是一個方法,那麼js會向執行棧中新增這個方法的執行環境,然後進入這個執行環境繼續執行其中的程式碼。當這個執行環境中的程式碼 執行完畢並返回結果後,js會退出這個執行環境並把這個執行環境銷燬,回到上一個方法的執行環境。這個過程反覆進行,直到執行棧中的程式碼全部執行完畢。
栗子
//(1) console.log(1) //(2) setTimeout(()=>{ console.log(2) },100) //(3) console.log(3)
所以結果是 1 3 2;
注意:setTimeout/Promise等我們稱之為任務源。而進入任務佇列的是他們指定的回撥;
上面的迴圈只是一個宏觀的表述,實際上非同步任務之間也是有不同的,分為 宏任務(macro task) 與 微任務(micro task),最新的標準中,他們被稱為 task與 jobs
下面我們再詳細講解一下執行過程:
執行棧在執行的時候,會把宏任務放在一個宏任務的任務佇列,把微任務放在一個微任務的任務佇列,在當前執行棧為空的時候,主執行緒會 檢視微任務佇列是否有事件存在。如果微任務佇列不存在,那麼會去宏任務佇列中 取出一個任務 加入當前執行棧;如果微任務佇列存在,則會依次執行微任務佇列中的所有任務,直到微任務佇列為空(同樣,是吧佇列中的事件加到執行棧執行),然後去宏任務佇列中取出最前面的一個事件加入當前執行棧...如此反覆,進入迴圈。
注意:
栗子
//(1) setTimeout(()=>{ console.log(1) // 宏任務 },100) //(2) setTimeout(()=>{ console.log(2) // 宏任務 },100) //(3) new Promise(function(resolve,reject){ //(4) console.log(3) // 直接列印 resolve(4) }).then(function(val){ //(5) console.log(val); // 微任務 }) //(6) new Promise(function(resolve,reject){ //(7) console.log(5) // 直接列印 resolve(6) }).then(function(val){ //(8) console.log(val); // 微任務 }) //(9) console.log(7) // 直接列印 //(10) setTimeout(()=>{ console.log(8) // 宏任務,單比(1)(2)宏任務早 },50)
上面的程式碼在node和chrome環境的正確列印順序是 3 5 7 4 6 8 1 2
下面分析一下執行過程:
注:因為渲染也是宏任務,需要在一次執行棧執行完後才會執行渲染,所以如果執行棧中同時有幾個同步的改變同一個樣式的程式碼,在渲染時只會渲染最後一個。
相關推薦:
以上就是經典技巧之JavaScript的單執行緒和非同步的詳細內容,更多請關注TW511.COM其它相關文章!