如何像Promise.all/allSettled那样并行执行多个同步函数?
关于同步函数“并行”执行的疑问解答
问题背景
现有同步函数:
const append = (input: string): string => input + ' hi';
已知若append()返回Promise时,可这样写:
const result = await Promise.all(['foo', 'bar', 'baz'].map(async x => append(x)));
结合JavaScript单线程特性,有三个疑问:
- 尝试并行执行同步的
append()是否有收益? - 该如何实现真正的“并行”?
- 下面这种写法是否不合理?
const result = await Promise.all(['foo', 'bar', 'baz'].map(x => append(x)));
具体解答
1. 同步函数“并行”执行没有任何收益
JavaScript的单线程机制决定了所有同步代码都在主线程的事件循环里依次执行,不存在真正的并行。哪怕用Promise.all包裹同步函数的执行结果,这些同步函数也会在map遍历的过程中逐个同步跑完,不会同时运行,自然也不会有性能提升。
比如你写的['foo', 'bar', 'baz'].map(x => append(x)),调用map的时候就已经把三个append执行完了,得到的是一个普通字符串数组,后续的Promise.all只是做了无意义的Promise包装,全程没有“并行”效果。
2. 让CPU密集型同步函数实现真正并行的方法
如果append是CPU密集型的同步函数(比如复杂计算),想利用多核CPU的能力,只能通过Web Worker实现。Web Worker允许在后台独立线程中运行脚本,和主线程互不阻塞,这才是真正意义上的并行处理。
简单示例:
- 主线程代码:
// 创建Worker实例 const worker = new Worker('worker.js'); // 发送待处理数据给Worker worker.postMessage(['foo', 'bar', 'baz']); // 接收Worker返回的处理结果 worker.onmessage = (e) => { console.log('最终结果:', e.data); };
- worker.js代码:
const append = (input) => input + ' hi'; self.onmessage = (e) => { // 在后台线程中批量处理数据 const result = e.data.map(append); // 将结果传回主线程 self.postMessage(result); };
3. 你提到的写法确实不合理
const result = await Promise.all(['foo', 'bar', 'baz'].map(x => append(x)));
这段代码里,map已经同步完成了所有append的执行,得到的是['foo hi', 'bar hi', 'baz hi']这个普通数组,Promise.all只是把数组里的每个值包装成已resolve的Promise,最后await得到的还是原数组。
这种写法完全是多此一举,既没实现并行,还额外增加了Promise包装的开销,直接写const result = ['foo', 'bar', 'baz'].map(x => append(x));就足够了。
内容的提问来源于stack exchange,提问作者Getting There
相关产品推荐
相关产品推荐

