js执行机制
在寫js代碼的時候我們往往都希望js代碼的執行順序是按照自己所想那樣執行,但結果總事與愿違。所以今天就想花時間搞懂js的事件執行機制到底是什么樣的。
EventLoop事件循環機制
js中事件分為宏任務和微任務兩類,任務又分為同步任務和異步任務。他們之間的執行順序將依次進行說明
js中事件的同步異步的執行順序
js中事件分為兩類
- 同步事件
- 異步事件
- js執行順序:先執行同步再執行異步
那么等到什么時候才能執行呢?就是等到主線程的任務執行完畢為空的時候。那我們怎么知道什么時候主線程為空呢?js引擎存在monitoring process進程,會持續不斷的檢查主線程執行棧是否為空,一旦為空,就會去Event Queue那里檢查是否有等待被調用的函數。 用流程圖來概括上述步驟:
- 代碼示例
js中事件的宏任務與微任務的執行順序
js中任務分為兩類
- 宏任務:包括整體代碼script,setTimeout,setInterval
- 微任務:Promise.then(非new Promise),process.nextTick(node中)
- js執行順序:先執行宏任務再執行微任務
用流程圖表示上述流程:
- 代碼示例
現在看一個比較復雜的例子
console.log('1'); setTimeout(function() {console.log('2');process.nextTick(function() {console.log('3');})new Promise(function(resolve) {console.log('4');resolve();}).then(function() {console.log('5')}) }) 輸出: 1 2 4 3 5 復制代碼js中的同步和異步
大家都知道js是是一門單線程語言,所以他的語句肯定是一句一句執行的。但是js中又存在同步操作和異步操作,那么就會有疑問,js是如何通過單線程的方式來實現異步操作的呢?
什么是同步操作
當函數執行的時候,按照函數內部的順序依次執行,比如:如果此調用的函數是很耗時的,但它依然會等待調用函數的返回值,直到拿到預期的結果(即拿到了預期的返回值或者看到了預期的效果)為止才會執行后面的操作,那么這個函數就是同步的。
//在函數返回時,獲得了預期值,即2的平方根 Math.sqrt(2); //在函數返回時,獲得了預期的效果,即在控制臺上打印了'hello' console.log('hello');復制代碼什么是異步操作
如果函數是異步的,發出調用之后,馬上返回,但是不會馬上返回預期結果。調用者不必主動等待,當被調用者得到結果之后會通過回調函數主動通知調用者。
//讀取文件 fs.readFile('hello.txt', 'utf8', function(err, data) {console.log(data); }); //網絡請求 var xhr = new XMLHttpRequest(); xhr.onreadystatechange = xxx; // 添加回調函數 xhr.open('GET', url); xhr.send(); // 發起函數 復制代碼上述示例中讀取文件函數 readFile和網絡請求的發起函數 send都將執行耗時操作,雖然函數會立即返回,但是不能立刻獲取預期的結果,因為耗時操作交給其他線程執行,暫時獲取不到預期結果(后面介紹)。而在JavaScript中通過回調函數 function(err, data) { console.log(data); }和 onreadystatechange ,在耗時操作執行完成后把相應的結果信息傳遞給回調函數,通知執行JavaScript代碼的線程執行回調。
瀏覽器
前面說到js是一門單線程語言,他是怎么實現異步操作的呢。JS的運行通常是在瀏覽器中進行的,具體由JS引擎去解析和運行。下面我們來具體了解一下瀏覽器。 瀏覽器的內核是多線程的。 一個瀏覽器通常由以下幾個常駐的線程:
- 渲染引擎線程:顧名思義,該線程負責頁面的渲染
- JS引擎線程:負責JS的解析和執行
- 定時觸發器線程:處理定時事件,比如setTimeout, setInterval
- 事件觸發線程:處理DOM事件
- 異步http請求線程:處理http請求
需要注意的是,渲染線程和JS引擎線程是不能同時進行的。 渲染線程在執行任務的時候,JS引擎線程會被掛起。因為JS可以操作DOM,若在渲染中JS處理了DOM,瀏覽器可能就不知所措了。
JS引擎可以說是JS虛擬機,負責JS代碼的解析和執行。之所以說JavaScript是單線程,就是因為瀏覽器在運行時只開啟了一個JS引擎線程來解析和執行JS。那為什么只有一個引擎呢?如果同時有兩個線程去操作DOM,瀏覽器是不是又要不知所措了。 所以,雖然JavaScript是單線程的,可是瀏覽器內部不是單線程的。一些I/O操作、定時器的計時和事件監聽(click, keydown...)等都是由瀏覽器提供的其他線程來完成的。也就是之前說的Event Queue。
參考文章
JavaScript異步機制詳解
這一次,徹底弄懂 JavaScript 執行機制
簡單總結下JS中EventLoop事件循環機制
總結
- 上一篇: 程序员写了段代码,自称完美! 网友: 我
- 下一篇: 记一次简单的sql优化