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事件机制),这样看起来就行是同时执行的一样,实现了并发的操作,而不是同时执行代码片段,这是并行的概念。

今天你学习了吗!!!
原文地址:https://www.cnblogs.com/nayek/p/12927213.html