首先我放在文章的開頭,重點說兩點:javascript
好了,那麼咱們開始這篇文章的主要內容,既然說js 是單線程,那就是在執行代碼的時候是從上往下執行的,咱們來看一段代碼吧:java
setTimeout(function(){
console.log('定時器開始')
});
new Promise(function(resolve){
console.log('Promise開始');
resolve();
}).then(function(){
console.log('執行then函數')
});
console.log('代碼執行結束');
複製代碼
看到上面的代碼,可能你們給出的答案是:'定時器開始','Promise開始','執行then函數','代碼執行結束'。那麼咱們驗證一下,輸出結果倒是:ios
看到這樣的答案,咱們仍是研究一下他的執行機制吧,至於預解析我後面會單獨發一篇文章單獨說,這裏我們就主要看後面的執行機制了,咱們說JavaScript是一個單線程語言,那他的 "多線程" 是咋來的,都是模擬出來的,一會咱們來看看這個"多線程的紙老虎"。ajax
既然是單線程,那麼咱們能夠想到,好比去銀行辦理業務,到了那裏要去排隊一個一個辦理,一樣的JavaScript的任務也是一個一個執行,若是前面一個用時很長,那後面哪個就得等着,等到前面的執行完再繼續。如今咱們在打開某一個網站的時候,一般會看到有些圖片加了背景圖,由於頁面中有些圖片,視頻,大批量的數據很是耗時,若是網速很差的電腦去打開,那想而知,空白啦~因此有了如今的 同步 和 異步!~axios
axios.post('/user', { name: 'fly', age: '30' })
.then(function (response) {
console.log(response);
})
console.log('代碼執行結束');
複製代碼
相信setTimeout你們並不陌生,在工做中可能也會用到,異步函數,還能延遲執行~promise
setTimeout(() => {
console.log('執行setTimeout');
},3000)
console.log('執行console');
複製代碼
按照咱們前面的思路,先執行console.log('執行console');而後執行console.log('執行setTimeout');答案沒錯,那再變換一下:瀏覽器
setTimeout(() => {
abc();
},3000)
exercise(100000000);//假設有個運動函數,須要時間很長...並且不固定...大於3秒,可能10秒
複製代碼
那麼咱們在運行結果,發現3秒後並無執行console.log('執行setTimeout');bash
上面的流程走完,咱們知道setTimeout這個函數,是通過指定時間後,把要執行的任務(本例中爲abc())加入到Event Queue中,又由於是單線程任務要一個一個執行,若是前面的任務須要的時間過久,那麼只能等着,致使真正的延遲時間遠遠大於3秒。有時候咱們會看到這樣的形式setTimeout(function(),0); 0秒是否是當即就執行了呢?其實並非多線程
那他的意識是說,不須要多少秒進入Event Queue ,待主線程任務走完,就回去執行。 仍是剛纔的例子:異步
setTimeout(() => {
abc();
},0)
console.log('執行console');
// 1.執行console 2.abc()
複製代碼
這裏說一下,其實看到有筆者說,setTimeout有最小時間間隔限制,HTML5標準爲4ms,小於4ms按照4ms處理,可是每一個瀏覽器實現的最小間隔都不一樣。 setInterval的最短間隔時間是10毫秒,也就是說,小於10毫秒的時間間隔會被調整到10毫秒。這裏先記下吧。
兩個定時器兄弟,原理同樣,只不過setInterval會每隔指定的時間將註冊的函數置入Event Queue。若是前面的任務時間過長,也會等待,不過這裏注意一點,若是其餘的函數執行時間過長,定時器會執行完畢會把這些任務從時間列表拿到事件隊列,若是時間唱的函數執行後,超出了延時執行的時間,那麼就會挨個的拿到主程序執行,看不出延時時間了。
這裏簡單說一下Promise的做用,細節就很少說了(還須要總結好多...),Promise對象是用於異步操做的。在實際的開發中,咱們是否是會遇到這種狀況:
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('第一個數據返回成功!');
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('第二個數據返回成功!');
...若是還有再繼續
}
})
}
})
複製代碼
看到這段代碼,應該不陌生吧,相信你們必定遇到過,"看着還不錯,挺好的~~~"!我信你個gui,糟老頭子壞得很~,那如今Promise派上用場了:
function abc(url,param){
return new Promise(function (resolve, reject) {
request(url, param, function(){
resolve('數據請求成功了');
}, reject);
});
}
abc.then(function(data){
console.log(date);//'第一個數據請求成功了';
return new Promise(function (resolve, reject) {
request(url, param, function(){
resolve('數據請求成功了');
}, reject)
});
}).then(function(){
console.log(date);//'第二個數據請求成功了';
});
複製代碼
這裏不過多說Promise 的用法了,繼續咱們的正題,除了廣義的同步任務和異步任務,咱們對任務有更精細的定義:
不一樣類型的任務會進入對應的事件隊列Event Queue,好比setTimeout和setInterval會進入相同的Event Queue。 Promise和process.nextTick會進入相同的。
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
resolve();
}).then(function() {
console.log('then');
})
console.log('console');
複製代碼
執行結果爲:promise,console,then,setTimeout
事件循環,宏任務,微任務的關係如圖(這裏看到不少做者用到的一張圖,我也那過來吧,謝謝圖片做者):
那下面就拿到一段代碼了,在網上也能看到:
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')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
附上輸出結果:1,7,6,8,2,4,3,5,9,11,10,12
複製代碼
在此要感謝網上看到的各位做者的文章(重點看到的csdn,子曉),以爲寫的很不錯,這裏也仿照着來記錄一下,也加了一下本身見解,但願能給更多的人帶來幫助~~~