那就先問個問題吧😁。javascript
單線程意思就是說同一個時間只能作一件事。那這樣的話效率不是很低?也沒有啦,其實javascript的單線程特色是跟他的用途有關的。做爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操做DOM。假如不是單線程的話,在一個線程當咱們在給某個DOM節點增長內容的時候,另外一個線程正在刪除這個DOM節點的內容,那還得了,那不是亂套了嗎。因此javascript只能是單線程。html
若是在一個函數返回的時候,調用者就可以獲得預期結果(即拿到了預期的返回值或者看到了預期的效果),那麼這個函數就是同步的。java
用代碼解釋一下:node
console.log('Hello');
複製代碼
若是在函數返回時,就看到了預期的效果:在控制檯打印了Helloajax
若是在函數返回的時候,調用者還不可以獲得預期結果,而是須要在未來經過必定的手段獲得,那麼這個函數就是異步的。promise
代碼解釋:瀏覽器
fs.readFile('test.txt', 'utf8', function(err, data) {
console.log(data);
});
複製代碼
在上面的代碼中,咱們但願經過fs.readFile函數讀取文件foo.txt中的內容,並打印出來。可是在fs.readFile函數返回時,咱們指望的結果並不會發生,而是要等到文件所有讀取完成以後。若是文件很大的話可能要很長時間。異步
同步方法調用一旦開始,調用者必須等到方法調用返回後,才能繼續後續的行爲。svg
異步方法調用更像一個消息傳遞,一旦開始,方法調用就會當即返回,調用者就能夠繼續後續的操做。而,異步方法一般會在另一個線程中,「真實」地執行着。整個過程,不會阻礙調用者的工做。函數
上面說過了javascript裏面的任務有兩種,同步任務和異步任務。
同步任務是指:在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務。
異步任務指的是,不進入主線程、而進入"任務隊列"的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行。
先看個小栗子吧:
console.log("a");
setTimeout(function () {
console.log("b");
},0);
console.log("c");
//a
//c
//b
複製代碼
js中代碼從上往下執行,執行第一行代碼的時候控制檯輸出a,執行到第二行代碼的時候遇到了setTimeout函數,由於setTimeout函數是個異步函數,因此,瀏覽器會記住這個事件,添加到時間表中,以後把這個事件的回調函數入棧到任務隊列中。而此時主線程程序繼續往下運行,到了第五行:console.log("c"),執行這條,控制檯輸出c。這時候主線程空了,他會到任務隊列裏面去查找是否有能夠執行的任務,有的話直接拿出來執行,沒有的話會一直去詢問,等到有能夠執行的。
![](data:image/svg+xml;utf8,<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1280" height="970"></svg>) 這張圖片裏面已經畫出了js的事件循環的流程了。 流程:
事件循環其實就是入棧出棧的循環。上面例子中說到了setTimeout,那setInterval呢,Promise呢等等等等,有不少異步的函數。可是這些異步任務有分宏任務(macro-task)和微任務(micro-task):
macro-task包括: setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。
每一次Event Loop觸發時:
在瀏覽器瀏覽器和node中的執行不同。
任務隊列裏面是「先入先出」的。
console.log('global')
for (var i = 1;i <= 5;i ++) {
setTimeout(function() {
console.log(i)
},i*1000)
console.log(i)
}
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('then1')
})
setTimeout(function () {
console.log('timeout2')
new Promise(function (resolve) {
console.log('timeout2_promise')
resolve()
}).then(function () {
console.log('timeout2_then')
})
}, 1000)
複製代碼
控制檯輸出: ![](data:image/svg+xml;utf8,<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="668" height="273"></svg>) 這個博客可以很是好的加深理解:深刻理解 JavaScript 事件循環(一)— event loop
這裏主要是講了在瀏覽器端js事件循環。這篇文章能夠幫助更好的理解node和瀏覽器環境下不一樣的事件循環:瀏覽器和Node不一樣的事件循環(Event Loop)