先看一道有意思的題目:想一下執行的過程和結果
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test() {
list.forEach(async x => {
const res = await square(x)
console.log(res)
})
}
test()
以上代碼執行情況是:在一秒后直接輸出1、4、9
你可能期望的是一次循環走完后,再走下一次循環,然而現實卻並不是這樣。因為forEach只會將異步的代碼執行了,但是並不會等待回調的結果,所以加了await也是無效的。
forEach在執行異步的時候類似並發執行,假設你在這遍歷十次,就好像十次同時都去執行了一樣,但是JavaScript是單線程的它不存在同時執行的概念。
-
這里需要先區分一下並發和並行的概念。
- 並發(concurrency):例如Node.js早期就是以高並發的能力而聞名的,雖然現在GO語言等適合做高並發,
- 並行(parallelism):同時執行的概念是並行里才存在的,而並發並不存在同時執行的概念,只有支持多線程和多進程的語言才可以執行並行。
-
Python 也是單線程的,雖然存在偽線程通過new Thread()實現
-
Java和C#中是有多線程的,多線程需要涉及線程同步的概念,這里就需要鎖 lock 的機制。
-
JavaScript是單線程機制,但是為何可以實現並發的操作。(宏任務、微任務)
-
單線程的機制實質還是因為現在CPU運算速度足夠快,在代碼快速運行時看起來像是同時運行的樣子,然而並不是同時執行的。
-
CPU密集型操作:JavaScript不適合做CPU密集型的操作,因為會使CPU負載過高,導致代碼執行阻塞。
-
資源密集型操作:例如網絡請求、查詢數據庫、讀寫文件。