JavaScript 单线程原理与异步编程机制
笔记哥 /
04-16 /
38点赞 /
0评论 /
324阅读
## JavaScript 单线程原理与异步编程机制
### 为什么 JavaScript 是单线程?
JavaScript 被设计成单线程,简单来说就是 —— **浏览器里干活儿只能一个接一个排着队来,没法同时多开窗口摸鱼。**
#### 举个栗子:
你点按钮 → 网页要弹个提示 → 这时候如果网页还在加载数据 → 弹提示就得等加载完 → **单线程 = 一次只能干一件事**。
#### 为啥这么设计?
- 最初网页交互简单(填表单、点按钮),单线程够用。
- 避免多线程打架(比如两个线程同时改同一个按钮的状态)。
#### 单线程的优点:
- **开发简单**:避免了多线程中的数据竞争、死锁等复杂问题。
- **调试方便**:执行顺序清晰明确,便于排查问题。
- **适合 I/O 密集型任务**:大多数 JS 任务(如事件处理、请求响应)并不需要多核计算资源。
#### 单线程的缺点:
- **阻塞风险高**:一旦有耗时操作(如大数据计算、死循环等),会卡住主线程,导致页面卡顿或无响应。
- **无法利用多核 CPU**:在默认模式下,不能并行计算,浪费了现代多核处理器的能力。
* * *
### JavaScript 如何实现高并发与多线程?
虽然 JS 是单线程执行模型,但通过浏览器或 Node.js 提供的机制,我们可以实现“**伪并发**”或“多线程模拟”,主要方式如下:
#### ✅ 异步操作(等加载时先干别的)
- **原理**:任务被挂起,等待资源时让出主线程,通过事件队列机制在任务完成后重新调度执行。
- **常用方式**:
- `setTimeout` / `setInterval`
- `Promise`
- `async/await`
- Ajax / Fetch API
#### ✅ Web Worker(开小号偷偷干活)
- 开启一个独立的线程运行 JS 脚本,不影响主线程。
- 适用于大计算任务、离线数据预处理等。
- 与主线程通信使用 `postMessage()` / `onmessage`
```js
// main.js
const worker = new Worker("worker.js")
worker.postMessage("开始计算")
worker.onmessage = (e) => {
console.log("子线程结果:", e.data)
}
```
```js
// worker.js
onmessage = function (e) {
// 执行密集任务
let sum = 0
for (let i = 0; i < 1e8; i++) sum += i
postMessage(sum)
}
```
#### ✅ Node.js 中的 Worker Threads
- 使用 `worker_threads` 模块在后端实现多线程能力,适合 CPU 密集型场景。
#### ✅ 任务拆碎(把大活切成小碎活穿插着做)
- 利用 `requestIdleCallback`、`setTimeout` 分片处理数据,减少卡顿。
* * *
### 异步与同步的区别
#### 同步(Synchronous)
- 执行顺序严格,必须等待上一个任务完成后才能执行下一个。
- 阻塞主线程。
```js
console.log("A")
document.querySelector("button").click() // 阻塞直到点击
console.log("B")
```
#### 异步(Asynchronous)
- 后台处理任务,不阻塞主线程,通过回调或事件通知结果。
```js
console.log("A")
setTimeout(() => console.log("B"), 1000)
console.log("C")
// 输出顺序:A -> C -> B
```
* * *
### Promise、async 和 await 的理解与使用
#### Promise
- 用于封装一个异步操作,避免回调地狱。
- 有三种状态:`pending`(等待中)、`fulfilled`(已完成)、`rejected`(已拒绝)
- 通过 `.then()` / `.catch()` 链式处理结果。
```js
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true
success ? resolve("数据加载成功") : reject("失败")
}, 1000)
})
}
fetchData()
.then((data) => console.log(data))
.catch((err) => console.error(err))
```
#### async/await
- 是 `Promise` 的语法糖,让异步代码写起来像同步代码。
- 只能在 `async` 函数中使用。
- 使用 `try/catch` 更方便地处理异常。
```js
async function getData() {
try {
const data = await fetchData()
console.log("结果:", data)
} catch (err) {
console.error("出错了:", err)
}
}
getData()
```
* * *
### 总结
| 技术/特性 | 描述 |
| --- | --- |
| 单线程模型 | JS 默认仅一个主线程,任务顺序执行 |
| 异步操作 | 不阻塞主线程,通过事件队列执行回调 |
| Web Worker | 浏览器中模拟多线程,适合重任务 |
| Node WorkerThreads | 后端的多线程计算方案 |
| 任务拆分 | 将大任务拆成小块,分帧执行减轻压力 |
| Promise | 管理异步逻辑,避免回调地狱 |
| async/await | 让异步代码更像同步,提升可读性 |
>
>
> 总之,单线程就像收银台只有一个店员,但现代网页用各种办法让这个店员手脚麻利到飞起。
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2329
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利
- 相关联分享
- JavaScript 中防抖和节流的多种实现方式及应用场景
- JavaScript 条件语句中善用 return 让代码更清晰
- JavaScript 3 种书写位置及 script 标签的正确存放位置
- JavaScript 的各种调试方法
- JavaScript 循环结构注意事项
- JavaScript 运算符 == 和 === 有什么区别?
- JavaScript 数据类型与类型转换
- 一个神奇的JS代码,让浏览器在新的空白标签页运行我们 HTML 代码(createObjectURL 的妙用)
- JavaScript 的应用领域
- JavaScript 单线程原理与异步编程机制
- JavaScript 各种对象定义与对象取值方法
- JavaScript 变量声明 var、let、const 区别
- JavaScript 各种数组定义与数组取值方法
- 使用Vite创建一个动态网页的前端项目