浅谈JavaScript 单线程防阻塞的原理

 更新时间:2025年09月04日 09:16:14   作者:自信的飞  
JavaScript是单线程语言,通过事件循环实现异步操作,宏任务与微任务分层处理,微任务优先执行,回调函数用于处理耗时操作,确保主线程不阻塞,下面就来具体介绍一下

JavaScript 是一种单线程语言,这意味着它一次只能执行一个任务。这种设计可能会导致一些问题,比如当遇到耗时的操作时,整个程序可能会被阻塞。为了解决这个问题,JavaScript 使用了事件循环和回调函数的机制,实现了非阻塞式的异步操作。

事件循环

JavaScript 有一个事件队列,用于存放需要执行的任务。事件循环不断地检查这个事件队列,当队列中有可执行的任务时,就从队列中取出任务执行。

当 JavaScript 遇到耗时的操作(如 I/O 操作)时,它会将这些操作交给浏览器或 Node.js 运行时处理,并继续执行事件循环中的其他任务。这样可以确保主线程不会被阻塞,保持程序的响应性和交互性。

宏任务和微任务

事件队列中的任务分为两种类型:宏任务微任务

  • 宏任务包括常见的 JavaScript 代码、setTimeout、setInterval 等。这些任务会被添加到事件队列的末尾,等待事件循环执行。
  • 微任务包括 Promise 的回调、process.nextTick (Node.js) 等。这些任务会被添加到当前宏任务执行完成后的微任务队列中,优先于下一个宏任务执行。

事件循环在执行一个宏任务后,会检查并执行所有的微任务队列,然后再执行下一个宏任务。这种机制确保了微任务可以更快地得到执行,提高了程序的响应性。

回调函数

当耗时的操作完成时,浏览器或 Node.js 运行时会触发一个事件,并将相应的回调函数放入事件队列中。

事件循环会检测到这个回调函数,并从队列中取出执行它。这就实现了非阻塞式的异步操作,防止单线程的 JavaScript 被耗时的操作阻塞。

实际应用

这种事件循环、宏任务和微任务的机制在 JavaScript 编程中广泛应用:

  1. 网页交互: 在网页开发中,我们经常使用回调函数来处理用户交互,如点击事件、表单提交等。这些操作通常不会阻塞主线程,确保页面保持高度响应性。
  2. 网络请求: 当发送 AJAX 请求时,我们通常会使用回调函数来处理服务器的响应。这样可以确保在请求过程中,用户仍然可以与页面进行交互。
  3. 定时器setTimeout() 和 setInterval() 函数也利用了事件循环的机制。它们会将定时器任务添加到事件队列中,等待执行。
  4. Node.js 中的异步操作: Node.js 也是基于事件循环和回调函数的机制实现异步操作,如文件 I/O、数据库查询等。这确保了 Node.js 应用程序可以高效地处理大量并发请求。

此外,还有一些其他的应用场景:

  1. 事件驱动模型: JavaScript 的事件循环机制很适合实现事件驱动模型,这在 Web 开发和 Node.js 中广泛应用。
  2. 错误处理: 当异步操作发生错误时,可以通过回调函数的方式进行错误处理,避免整个程序崩溃。
  3. 流式处理: 在处理大量数据时,可以使用流的方式进行异步处理,提高性能和内存利用率。

javaScript 如何实现高并发与多线程?

虽然 JS 是单线程执行模型,但通过浏览器或 Node.js 提供的机制,我们可以实现“伪并发”或“多线程模拟”,主要方式如下:

✅ 异步操作(等加载时先干别的)

  • 原理:任务被挂起,等待资源时让出主线程,通过事件队列机制在任务完成后重新调度执行。
  • 常用方式
    • setTimeout / setInterval
    • Promise
    • async/await
    • Ajax / Fetch API

✅ Web Worker(开小号偷偷干活)

  • 开启一个独立的线程运行 JS 脚本,不影响主线程。
  • 适用于大计算任务、离线数据预处理等。
  • 与主线程通信使用 postMessage() / onmessage
// main.js
const worker = new Worker("worker.js")
worker.postMessage("开始计算")
worker.onmessage = (e) => {
  console.log("子线程结果:", e.data)
}
// 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 密集型场景。

✅ 任务拆碎(把大活切成小碎活穿插着做)

  • 利用 requestIdleCallbacksetTimeout 分片处理数据,减少卡顿。

异步与同步的区别

同步(Synchronous)

  • 执行顺序严格,必须等待上一个任务完成后才能执行下一个。
  • 阻塞主线程。
console.log("A")
document.querySelector("button").click() // 阻塞直到点击
console.log("B")

异步(Asynchronous)

  • 后台处理任务,不阻塞主线程,通过回调或事件通知结果。
console.log("A")
setTimeout(() => console.log("B"), 1000)
console.log("C")
// 输出顺序:A -> C -> B

Promise、async 和 await 的理解与使用

Promise

  • 用于封装一个异步操作,避免回调地狱。
  • 有三种状态:pending(等待中)、fulfilled(已完成)、rejected(已拒绝)
  • 通过 .then() / .catch() 链式处理结果。
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 更方便地处理异常。
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让异步代码更像同步,提升可读性

总之,单线程就像收银台只有一个店员,但现代网页用各种办法让这个店员手脚麻利到飞起。

到此这篇关于浅谈JavaScript 单线程防阻塞的原理的文章就介绍到这了,更多相关JavaScript 单线程防阻塞内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • javascript跟随滚动效果插件代码(javascript Follow Plugin)

    javascript跟随滚动效果插件代码(javascript Follow Plugin)

    这篇文章介绍了javascript跟随滚动效果插件代码(javascript Follow Plugin),有需要的朋友可以参考一下
    2013-08-08
  • 概述一个页面从输入URL到页面加载完的过程

    概述一个页面从输入URL到页面加载完的过程

    本文主要对一个页面从输入 URL 到页面加载完的过程中都发生了什么事情进行概述,对我们学习网络语言有一定的帮助,下面就跟小编一起来看下吧
    2016-12-12
  • JavaScript中的函数申明、函数表达式、箭头函数

    JavaScript中的函数申明、函数表达式、箭头函数

    js中的函数可以通过几种方式创建,具体创建方法通过实例代码给大家介绍的非常详细,文中通过例子给大家介绍了函数声明和表达式之间的差别,感兴趣的朋友跟随小编一起看看吧
    2019-12-12
  • JavaScript动态添加数据到表单并提交的几种方式

    JavaScript动态添加数据到表单并提交的几种方式

    这篇文章主要介绍了JavaScript动态添加数据到表单并提交,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-06-06
  • 两种常用的javascript数组去重方法思路及代码

    两种常用的javascript数组去重方法思路及代码

    第一种是常规的方法:建一个新的数组存放结果,for循环中每次从原数组中取出一个元素,用indexOf查找新数组中是否有该元素,至于第二种详细的看下本文哦
    2013-03-03
  • 微信小程序开发技巧汇总

    微信小程序开发技巧汇总

    这篇文章主要介绍了微信小程序开发技巧汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • 详解小程序循环require之坑

    详解小程序循环require之坑

    这篇文章主要介绍了详解小程序循环require之坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • js控制鼠标事件移动及移出效果显示

    js控制鼠标事件移动及移出效果显示

    鼠标事件的移动及移出效果都可以使用js来自定义,下面有个示例,实,效果为当事件发生改变时背景颜色也随着改变
    2014-10-10
  • JavaScript实现楼梯滚动特效(jQuery实现)

    JavaScript实现楼梯滚动特效(jQuery实现)

    这篇文章主要为大家详细介绍了JavaScript实现楼梯滚动特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • IE的有条件注释判定IE版本详解(附实例代码)

    IE的有条件注释判定IE版本详解(附实例代码)

    IE的有条件注释是一种专有的(因此是非标准的)、对常规(X)HTML注释的Miscrosoft扩展。顾名思义,有条件注释使你能够根据条件(比如浏览器版本)显示代码块(不一定就是css,也可以是html代码,甚至是JavaScript代码)。
    2012-01-01

最新评论