浅谈JavaScript面试题:从进程与线程到事件循环机制!!!

前言

在现代的Web开发中,深入理解进程与线程的概念,以及它们在浏览器中的应用至关重要。本文将探讨这些基本概念及其对JavaScript运行方式的影响,以及基于事件循环机制对代码执行顺序进行分析。

进程与线程:基础概念

  • 进程:进程是系统进行资源分配和调度的基本单位,是CPU运行指令和保存上下文所需的时间的集合。每个进程都有自己的独立内存空间。
  • 线程:线程是进程的一个实体,是CPU调度和分派的基本单位。它比进程更小,描述的是一段指令执行所需的时间。线程共享其所属进程的资源。

浏览器中的进程和线程

当在浏览器中新开一个Tab页面时,浏览器实际上是创建了一个新的进程。这个进程包含多个线程,协同工作以呈现和处理网页。这些线程包括:

  1. 渲染线程(GPU) :负责页面渲染。
  2. HTTP请求线程:处理网络请求。
  3. JavaScript引擎线程:执行JavaScript代码。

值得注意的是,渲染线程和JavaScript引擎线程是互斥的,这意味着当JavaScript代码执行时,页面渲染会暂停。

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        //一堆代码xxx
    </script>
</head>
<body>
    <div class="box"></div>
    //一堆代码
</body>
</html>

假设在这段html代码中的js代码部分,对DOM结构的样式进行了修改,而在下方的html代码中也对同一个DOM结构的样式进行了修改,就会引起冲突,所以当JavaScript代码执行时,页面渲染会暂停。

JS:一个单线程的语言

JavaScript是一个单线程的语言。在最初设计时,JavaScript主要用作浏览器脚本语言,考虑到降低功耗和减少性能占用,选择了单线程模型。单线程模型有其独特的优势:

  1. 节省内存:不需要像多线程那样分配大量线程资源。
  2. 无锁的概念:简化了程序设计,不需要处理复杂的线程同步问题,也减少了上下文切换的时间。

异步编程:宏任务与微任务

JavaScript的异步编程可以分为宏任务(macrotask)和微任务(microtask)。

  • 宏任务:包括script(整体代码), setTimeout, setInterval, setImmediate(在DOM结构加载完毕后执行的操作), I/O操作, UI渲染等。
  • 微任务:例如promise.then()(promise本身是同步的,但其then方法是异步的),MutationObserver(监听DOM变更),process.nextTick()。

Event Loop:事件循环机制

JavaScript的核心是基于事件循环的。它的工作原理是:

  1. 首先执行所有的同步代码(这是一个宏任务)。
  2. 将执行过程中遇到的宏任务代码和微任务代码分别放入宏任务队列和微任务队列。
  3. 当调用栈为空时,查看是否有异步代码需要执行。
  4. 执行所有的微任务。
  5. 如有必要,进行UI渲染。
  6. 执行下一个宏任务,开启下一轮事件循环。

接下来我们来分析一段代码的执行顺序:

javascript 复制代码
console.log('script start')
async function async1() {//async声明的函数返回的是一个promise对象,执行使相当于同步代码
    await async2() //浏览器给await开小灶,相当于紧跟在await后面的代码变为同步代码
    console.log('async1 end')
}
async function async2() {
    console.log('async2 end')
}
async1()
setTimeout(function () {
    console.log('setTimeout')
}, 0)
new Promise(resolve => {
    console.log('Promise')
    resolve()
})
    .then(function () {
        console.log('promise1')
    })
    .then(function () {
        console.log('promise2')
    })
console.log('script end')
  1. 首先执行第一行的代码,打印'script start'
  2. 然后执行函数async1的声明
  3. 接着执行函数async2的声明
  4. 执行async1函数的调用,打印'async2 end',将console.log('async1 end')放入微任务队列
  5. 将setTimeout放入宏任务队列
  6. 执行promise函数的逻辑,打印'Promise'
  7. 将第一个.then中的console.log('promise1')放入微任务队列
  8. 将第二个.then中的console.log('promise2')放入微任务队列
  9. 打印'script end'
  10. 按进入队列的顺序执行微任务队列(先进先出),打印'async1 end'打印'promise1'打印'promise2'
  11. 执行宏任务队列中的打印'setTimeout'

运行结果如下:

总结

通过深入理解进程与线程的概念,以及JavaScript的单线程特性和事件循环机制,开发者可以更有效地利用这些知识来编写高效且可维护的代码。实际的代码示例不仅帮助我们理解理论概念,而且还提供了实际应用的见解。希望这篇文章能够帮助您在JavaScript编程的旅程中迈出坚实的一步。


有什么说的不对的地方欢迎在评论区批评指正~

如果觉得写的不错,麻烦点个免费的赞吧!谢谢大家!

相关推荐
张拭心16 分钟前
程序员越想创业,越不要急着动手
前端·人工智能
舒一笑19 分钟前
在低配云服务器上实现自动化部署:Drone CI + Gitee Webhook 的轻量级实践
前端·后端·程序员
龙国浪子22 分钟前
从零到一:打造专业级小说地图设计工具的技术实践
前端·electron
一水鉴天44 分钟前
整体设计 定稿 之24+ dashboard.html 增加三层次动态记录体系仪表盘 之2 程序 (Q208 之2)
开发语言·前端·javascript
测试人社区-小明1 小时前
洞察金融科技测试面试:核心能力与趋势解析
人工智能·科技·面试·金融·机器人·自动化·github
IT_陈寒1 小时前
Java 21新特性实战:这5个改进让我的代码效率提升40%
前端·人工智能·后端
肠胃炎1 小时前
Chrome扩展截图功能实现
前端·chrome
二狗哈1 小时前
Cesium快速入门17:与entity和primitive交互
开发语言·前端·javascript·3d·webgl·cesium·地图可视化
xingzhemengyou11 小时前
python datetime模块使用
前端·python
GISer_Jing2 小时前
AI驱动营销增长:7大核心场景与前端实现
前端·javascript·人工智能