「JavaScript 是單線程、異步、非阻塞、解釋型腳本語言。」
進程:瀏覽器一個頁面就是新的一個進程,進程是CPU資源分配的最小單位(系統會給它分配內存);javascript
線程:線程包含在每一個進程內,線程是CPU調度的最小單位(線程是創建在進程的基礎上的一次程序運行單位,一個進程中能夠有多個線程);java
永遠只有JS引擎(JS內核)線程在執行JS腳本程序, 負責解析執行Javascript腳本程序的主線程(例如V8引擎)
因爲JavaScript是可操縱DOM的,若是在修改這些元素屬性同時渲染界面(即JS線程和UI線程同時運行),那麼渲染線程先後得到的元素數據就可能不一致了。
所以爲了防止渲染出現不可預期的結果,瀏覽器設置GUI渲染線程與JS引擎爲互斥的關係,當JS引擎執行時GUI線程會被掛起,GUI更新則會被保存在一個隊列中等到JS引擎線程空閒時當即被執行。node
單線程語言:JavaScript 的設計就是爲了處理瀏覽器網頁的交互(DOM操做的處理、UI動畫等),決定了它是一門單線程語言。【處理任務是一件接着一件處理,從上往下順序執行】web
若是有多個線程,它們同時在操做 DOM,那網頁將會一團糟。
當遇到計時器、DOM事件監聽或者是網絡請求的任務時,JS引擎會將它們直接交給** webapi,也就是瀏覽器提供的相應線程(如定時器線程爲setTimeout計時、異步http請求線程處理網絡請求)去處理,而JS引擎線程繼續後面的其餘任務,這樣便實現了異步非阻塞**。後端
JavaScript 中有同步代碼與異步代碼。api
因爲Es6 和node出現產生的微任務promise
console.log('script start') setTimeout(function() { console.log('timer over') }, 0) Promise.resolve().then(function() { console.log('promise1') }).then(function() { console.log('promise2') }) console.log('script end') // script start // script end // promise1 // promise2 // timer over
JS引擎線程首先執行主代碼塊。瀏覽器
每次執行棧執行的代碼就是一個宏任務,包括任務隊列(宏任務隊列)中的,由於執行棧中的宏任務執行完會去取任務隊列(宏任務隊列)中的任務加入執行棧中,即一樣是事件循環的機制。網絡
在執行宏任務時遇到Promise等,會建立微任務(.then()裏面的回調),並加入到微任務隊列隊尾。多線程
microtask必然是在某個宏任務執行的時候建立的,而在下一個宏任務開始以前,瀏覽器會對頁面從新渲染(task >> 渲染 >> 下一個task(從任務隊列中取一個))。同時,在上一個宏任務執行完成後,渲染頁面以前,會執行當前微任務隊列中的全部微任務。
也就是說,在某一個macrotask執行完後,在從新渲染與開始下一個宏任務以前,就會將在它執行期間產生的全部microtask都執行完畢(在渲染前)。
這樣就能夠解釋 "promise 1" "promise 2" 在 "timer over" 以前打印了。"promise 1" "promise 2" 作爲微任務加入到微任務隊列中,而 "timer over" 作爲宏任務加入到宏任務隊列中,它們同時在等待被執行,可是微任務隊列中的全部微任務都會在開始下一個宏任務以前都被執行完。
在node環境下,process.nextTick的優先級高於Promise,也就是說:在宏任務結束後會先執行微任務隊列中的nextTickQueue,而後纔會執行微任務中的Promise。
吃透這些例子 包你掌握js執行順序及promise知識:
https://www.jianshu.com/p/e585e737fb6f