### 異步基礎
#### 單線程和異步
* JS 是單線程語言,只能同時做一件事
* 瀏覽器和 nodejs 已支持 JS 啟動**進程**,如 Web Worker
* JS 和 DOM 渲染共用同一個線程,因為 JS 可修改 DOM 結構
* 異步不會阻塞代碼運行,同步會阻塞代碼執行
#### 回調地獄-callback hell

#### Promise 基礎


### 異步進階
#### JS 如何執行
* 從前到后,一行一行執行
* 如果某一行執行錯誤,則停止下面代碼的執行
* 先把同步代碼執行完,在執行異步
#### event loop(事件循環/事件輪循)
> JS 是單線程運行的,異步要基于回調來實現;event loop 就是異步回調的實現原理

* event loop 過程
* 同步代碼,一行一行放在 Call StacK 執行
* 遇到異步,會先“記錄”下,等待時機(定時、網絡請求)
* 時機到了,就移動到 Callback Queue
* 如 Call Stack 為空(即同步代碼執行完)Event Loop 開始工作
* 輪詢查找 Callback Queue,如有則移動到 Call Stack 執行
* 然后繼續輪詢查找(永動機一樣)
##### DOM 事件和 event loop
* 異步(setTimeout,ajax等)使用回調,基于 event loop
* DOM 事件(dom事件不是異步)也使用回調,基于 event loop
#### Promise 進階
* Promise 的三種狀態
* pending
* resolved
* rejected
* resolved 觸發 then 回調,rejected 觸發 catch 回調
* then 和 catch 改變狀態(沒有報錯,都返回resolved)
* then 正常返回 resolved,里面有報錯則返回 rejected
* **catch 正常返回 resolved**,里面有報錯則返回 rejected


#### async/await
* 產生背景
> 異步回調 callback hell ---> Promise then catch 鏈式調用,但也是基于回調函數 ---> **async\await是同步語法,徹底消滅回調函數**
* 立即調用函數表達式 [參考鏈接](https://developer.mozilla.org/zh-CN/docs/Glossary/IIFE) IIFE
```javascript
// 感嘆號,用來分割上一行(上一行沒分號結尾的話)
!(()=>{
console.log('')
})()
```
* async/await 只是一個語法糖
##### async/await 與promise 關系
* await 相當于 Promise then
* promise catch 可以使用 try catch 代替
* async 封裝 promise 返回 promise
執行循序例題
```javascript
async function async1() {
console.log('async start')
await async2() // await 后面,都可以看做是 callback 里的內容,即異步
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
async1()
console.log('script end')
```

```javascript
async function async1() {
console.log('async start')
await async2()
console.log('async1 end')
await async3()
console.log('async1 end 2')
}
async function async2() {
console.log('async2')
}
async function async3() {
console.log('async3')
}
console.log('script start')
async1()
console.log('script end')
```

#### for ... of
* for ... in 以及 forEach for 是常規的同步遍歷
* for ... of 常用于異步的遍歷
```javascript
function muti(num) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
const nums = [1, 2, 3]
// 同步遍歷
nums.forEach(async (i) => {
const res = await muti(i)
// 一瞬間同時打印1,4,9
console.log(res)
})
// 異步遍歷
!(async () => {
for (let i of nums) {
const res = await muti(i)
// 隔一秒打印一個
console.log(res)
}
})()
```
#### 宏任務 macroTask 和微任務 microTask
```javascript
console.log('start') // 1
setTimeout(() => {
console.log('宏任務') // 4
})
Promise.resolve().then(() => {
console.log('微任務') // 3
})
console.log('end') // 2
```
* 宏任務:setTimeout seInterval Ajax DOM 事件;**DOM 渲染后觸發**;微任務是 ES6 語法規定的
* 微任務:Promise async/await;**DOM 渲染前觸發**;宏任務是由瀏覽器規定的
* **微任務執行時機比宏任務要早**
##### event-loop 和 dom 渲染的關系

* 每次 Call Stack 清空(即每次輪詢結束),即同步任務執行完
* 都是 DOM 重新渲染的機會,DOM 結構如有改變則重新渲染
* 然后再去觸發下一次 Event Loop
```html
<div id="container"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
const $p1 = $('<p>一段文字</p>')
const $p2 = $('<p>一段文字</p>')
const $p3 = $('<p>一段文字</p>')
$('#container').append($p1).append($p2).append($p3)
console.log('length', $('#container').children().length)
alert('本次 call stach 結束,DOM 結構已更新,但尚未觸發渲染')
// (alert 會阻斷 js 執行,也會阻斷 DOM 渲染,便于查看效果)
</script>
```
##### 
題目
```javascript
async function async1() {
console.log('async1 start') // 2
await async2()
console.log('async1 end') // await 后面是回調,相當于then里面,微任務 6
}
async function async2() {
console.log('async2') // 3
}
console.log('script start') // 1
setTimeout(function () { // 宏任務
console.log('setTimeout') // 8
}, 0)
async1() //
// Promise 聲明中的代碼會立即執行
new Promise(function (resolve) {
console.log('promise1') // 4
resolve()
}).then(function () {
console.log('promise2') // 7
})
console.log('scrtpt end') // 5 所有同步代碼執行完畢、call stack清空,開始 event loop
// 同步代碼 -> 微任務 -> 嘗試觸發DOM渲染 -> 觸發 Event Loop 執行宏任務
```
