# 非同步機制
[ToC]
---
## JavaScript 為什麼不採用多執行緒
----
### 單執行緒的狀況下- 習慣的思維
```javascript=
const userTable = { '1': { money: 10000 } }
function withdraw (id, money) {
userTable[id].money -= money
}
function deposit (id, money) {
const currentMoney = userTable[id].money
currentMoney += money
userTable[id].money = currentMoney
}
```
```javascript=
withdraw('1', 10000) // 0
```
```javascript=
deposit('1', 1000) // 1000
```
----
### 多執行緒的狀況下- 沒有互斥鎖的狀況
```javascript=
const money1 = userTable[id].money
const money2 = userTable[id].money // *
money1 -= 10000
userTable[id].money = money1
money2 += 1000 // 認為餘額還是 10000
userTable[id].money = money2
// 11000, 現賺 10000 (也可能變 0)
```
---
## 非同步仍是必要的- 畫面凍結的問題
https://codesandbox.io/s/ui-blocking-r354l
---
## 我都要! 單執行緒+非同步機制
----
### Event Loop (事件循環機制)

```javascript=
function bar () { console.log('baz') }
function foo () { bar() }
setTimeout(() => { console.log('setTimeout') }, 1000)
setInterval(() => { console.log('setInterval') }, 5000)
foo()
```
----
### Render時機與畫面凍結
[為什麼要用 setTimeout, 只用 Promise.resolve 不可以嗎?](https://gitlab.com/cqbw_generic/web-frontend/emu/-/blob/develop/src/store/index.js#L389-391)
[何時使用 microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide#When_to_use_microtasks)
---
## 小試身手
- Task(Macrotask): setTimeout, requestAnimation ...
- Microtask: Promise.then, process.nextTick ...
```javascript=
setTimeout(() => {
console.log('setTimeout')
})
new Promise(resolve => {
console.log('promise executor')
resolve()
})
.then(() => {
console.log('promise then')
})
console.log('main')
```
---
## 總結
- 兩種不同的執行隊列: microtask queue、macrotask queue
- 瀏覽器會在下個 macrotask 執行前, 重新渲染 UI
- [升級 node 到 major 11 版本以上](https://juejin.im/post/5c3e8d90f265da614274218a)
---
## Q&A
---
## 歡迎來到真實世界
請寫出以下印出 0~9 的順序
```javascript=
async function async1() {
new Promise(async resolve => {
Promise.resolve()
.then(() => {
console.log(0)
resolve()
})
})
.then(() => {
console.log(1)
})
await async2()
console.log(2)
}
async function async2() {
async3()
console.log(3)
}
function async3() {
new Promise((resolve) => resolve())
.then(() => {
console.log(4)
})
Promise.resolve()
.then(() => {
console.log(5)
})
}
async1()
setTimeout(function() {
console.log(6)
}, 0)
new Promise(resolve => {
console.log(7)
resolve()
})
.then(function() {
console.log(8)
})
.then(function() {
console.log(9)
})
```
## 其他挑戰
- [螞蟻金服面試題](https://juejin.im/post/6860646761392930830)
---
## 參考來源、圖片來源
- [HTML spec.: Event loop processing model](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)
- [Use reject instead of throw - you cannot use throw asynchronously](https://stackoverflow.com/a/36222960/7122623)
- [Tasks, Microtasks and Schedules](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)
- [掘金: 微任務、宏任務與Event-Loop](https://juejin.im/post/5b73d7a6518825610072b42b)
- https://www.uniqlo.com/
<style>
p {
margin: 5px !important;
}
blockquote {
border-left: 10px solid #ddd;
font-size: 2.5rem;
}
blockquote > p {
margin-left: 5px;
}
:not(.overview) > .slides {
top: 0 !important;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
transform: none !important;
width: 90vw !important;
}
img {
display: inline;
}
</style>
{"metaMigratedAt":"2023-06-15T05:41:04.538Z","metaMigratedFrom":"Content","title":"非同步機制","breaks":true,"contributors":"[{\"id\":\"e77f9ae0-feb2-4c38-9ae8-f06f8655e3a4\",\"add\":14138,\"del\":10631}]"}