JavaScript 中的并发与多线程:从入门到精通
JavaScript 历史上是一种单线程语言,运行在事件驱动编程范式下。然而,现代 JavaScript(尤其是在 Node.js 环境中)提供了强大的工具来处理并发和多线程。在本文中,我们将深入探讨 Event Loop、Promises、async/await、Worker Threads 和集群的工作原理,以及如何使用这些机制来提高应用程序的性能。
1. Event Loop:JavaScript 并发的基础
Event Loop 是 JavaScript 异步模型的核心。它允许在不阻塞主执行线程的情况下处理多个操作。在 Node.js 中,Event Loop 管理任务队列(宏任务和微任务),实现非阻塞 I/O。
Event Loop 工作示例:
console.log('开始');
setTimeout(() => { console.log('定时器 1');}, 0);
process.nextTick(() => { console.log('nextTick');});
Promise.resolve().then(() => { console.log('Promise');});
console.log('结束');
// 输出:// 开始// 结束// nextTick// Promise// 定时器 1理解执行顺序很重要:同步代码 → 微任务(process.nextTick, Promise.then)→ 宏任务(setTimeout, setInterval)。
2. Promises 和 async/await:管理异步操作
Promises 是表示异步操作结果的对象。它们允许避免“回调地狱”并构建调用链。async/await 是 Promises 的语法糖,使异步代码看起来像同步代码。
使用 async/await 的示例:
const fetchData = async (url) => { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP 错误:${response.status}`); } return await response.json();};
const main = async () => { try { const data = await fetchData('https://api.example.com/data'); console.log('获取的数据:', data); } catch (error) { console.error('错误:', error.message); }};
main();这种方法允许使用 Promise.all() 并行执行多个异步操作:
const [user, posts] = await Promise.all([ fetchUser(userId), fetchPosts(userId)]);console.log(user, posts);3. Worker Threads:Node.js 中的真正多线程
从 Node.js 10.5.0 开始,worker_threads 模块提供了创建真正线程来执行 CPU 密集型任务的能力。每个 Worker 在独立的线程中运行,拥有自己的 V8 实例。
创建 Worker 的示例:
// main.jsconst { Worker } = require('worker_threads');
const runWorker = (workerData) => { return new Promise((resolve, reject) => { const worker = new Worker('./worker.js', { workerData });
worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) { reject(new Error(`Worker 以代码 ${code} 停止`)); } }); });};
const main = async () => { const result = await runWorker({ iterations: 1000000 }); console.log('结果:', result);};
main();// worker.jsconst { parentPort, workerData } = require('worker_threads');
const heavyComputation = (iterations) => { let result = 0; for (let i = 0; i < iterations; i++) { result += Math.sqrt(i); } return result;};
const result = heavyComputation(workerData.iterations);parentPort.postMessage(result);Worker Threads 非常适合会阻塞 Event Loop 的任务:图像处理、数学计算、解析大文件。