forEach中使用async await的问题
先看一道有意思的题目:想一下执行的过程和结果
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负载过高,导致代码执行阻塞。
-
资源密集型操作:例如网络请求、查询数据库、读写文件。
举例假设查询数据库需要3秒,这个时候JavaScript不会等待,因为这3秒是数据库的运算能力需要消耗的时间,跟JavaScript没有关系,所以这个时候JavaScript可以利用这3秒钟的时间去执行别的代码片段(这里就涉及到JavaScript中的Eventloop事件机制),这样看起来就行是同时执行的一样,实现了并发的操作,而不是同时执行代码片段,这是并行的概念。
今天你学习了吗!!!