首先,由於JavaScript語言是單線程的*(目標爲瀏覽器端,出生即爲單線程)*,因此就須要異步,不然JavaScript腳本智能自上而下執行,若是在上部存在一些極其複雜的代碼須要解析很長的時間的話,下面的代碼就會遭到阻塞,也就是用戶感覺到的卡死.javascript
因爲是單線程語言,因此JavaScript實現異步的方法是經過**事件循環(event loop)**來實現異步.html
console.log('I’m first one code!');
setTimeout(() => {
console.log('I’m setTimeout function code!');
})
console.log('I’m last one code! ');
複製代碼
這段代碼的運行結果爲java
I’m first one code!
I’m last one code!
I’m setTimeout function code!
複製代碼
因此,代碼並無是自上而下執行,setTimeout函數是延遲了一段時間,等其餘語句執行完了採起執行,這種狀況就爲異步。es6
根據上一部分咱們知道,JavaScript把事件分爲兩類:同步與異步api
因此JavaScript的執行機制實際上是:promise
這個循環即爲 event loop瀏覽器
咱們先看一段代碼bash
setTimeout(() => {
console.log('1');
});
new Promise((resolve) => {
console.log('2');
}).then( () => {
console.log('3');
});
console.log('4');
複製代碼
若是按照咱們剛纔的理解,這段代碼的結果應該爲 2,4,1,3異步
But unfortunately!他的結果爲 2,4,3,1async
這也引入了另外兩個概念:宏任務與微任務
因此任務應該分爲這兩類:
因此js的執行機制實際上是
先執行一個宏任務,過程當中若是遇到微任務先把他放到微任務的事件隊列中,當宏任務執行完畢後,再去查看微任務的事件隊列,將微任務一次執行完,執行完畢後再去進行下一個隊列的宏任務,以此循環.
借用一張圖演示
剛忽然發現已經繞遠了:car:,趕快漂移回原來的主題,async,一個在ES2017中提出的異步方案,有人說他是Generator函數的語法糖,只是把Generator函數的 * 替換爲 async,把yield替換爲await。咱們先不討論這句話說得對不對:speak_no_evil:,但它確實是基於了Generator的一種改進,它讓異步變得更簡單了。
若是要簡述的話,一旦你的函數前帶上了async,你的函數返回值就一定是promise對象.(他就像真香定律同樣是沒有能夠逃過的)就算你寫的函數裏返回的不是promise,他也會自動用Promise.resolve()包裝起來讓他成爲一個promise對象。
因此,若是咱們簡單理解async關鍵字的話,他其實就是給函數加上一個標識,說明這個函數內部有異步操做。
咱們再次簡單的介紹如下 await,await 其實等的是右側表達式的結果.
若是右側是一個函數,則是這個函數的返回值。若是是一個值則就爲此值.
咱們經過一個例子來"見識見識"它
async function fun1(){
console.log('fun1 is started!');
await fun2();
console.log('fun1 ending!');
}
async function fun2(){
console.log('fun2 is running!');
}
fun1();
console.log('script start');
複製代碼
咱們知道,await是經過執行到此時讓出線程,經過阻塞後面的代碼來執行,但咱們執行上面的代碼發現結果爲
fun1 is started!
fun2 is running!
script start
fun1 endding!
複製代碼
注意,這裏fun2先於"script start" 執行,因此 await 的那個表達式的執行順序實際上是從右到左,即爲執行了fun2後讀到了await關鍵字,而後阻塞後面的代碼,這點很是重要,由於以前由於"一旦遇到await就立馬退出線程,阻塞後面的代碼"的觀點,認爲 await也會阻塞他後面的那個表達式,但其實否則。
await 與 async 的關係就像魚和水, await必需要有async才能夠存在,而async卻不必定須要有await。
通常來講 await等到的右側表達式結果有兩種狀況:
Promise or Not Promise。
我的Github:Reaper622
歡迎學習交流