浏览器原理之浏览器机制

事件机制

一 事件是什么?事件模型?

事件 是浏览器或用户自身发出的某种特定交互的信号。这包括但不限于鼠标点击、按键操作、页面加载、滚动等。

事件模型 主要包括三个阶段:

  1. 捕获阶段:事件从文档根节点向下传递到目标节点,主要用于拦截事件。
  2. 目标阶段:事件到达目标节点。
  3. 冒泡阶段:事件从目标节点向上冒泡到文档的根节点。

二 如何阻止事件冒泡

在事件处理函数中调用event.stopPropagation()方法可以阻止事件冒泡。这会阻止事件进一步传播到父节点。

三 对事件委托的理解

事件委托 是一种利用事件冒泡原理来优化事件处理的技术。它基于这样一个事实:在冒泡阶段,事件会一路向上传播到父节点。因此,可以将事件监听器设置在父节点上,而不是每个子元素上。这样,当子节点上的事件被触发时,它会冒泡到父节点,并被那里的监听器捕获。

四 事件委托的使用场景

  • 大量元素的事件处理:例如,列表或表格中的每个项目如果都绑定事件处理器会导致内存占用过高。事件委托可以减少绑定的事件处理器数量。
  • 动态元素的事件处理:对于动态添加到页面的元素,如果它们的事件处理器是通过事件委托添加的,就无需在添加元素时反复绑定事件。

五 同步和异步的区别

  • 同步操作:调用某个函数后,必须等待这个函数执行完毕才能执行下一行代码。
  • 异步操作:调用非阻塞函数后,可以继续执行后续代码,而被调函数通常会在未来的某个时间点完成,不会立即返回结果。

六 对事件循环的理解

事件循环是一种程序结构,用于等待和发送消息和事件。一个简单的事件循环只需不断检查是否有事件发生,如果有,就取出事件并执行相应的逻辑。

七 宏任务和微任务分别有哪些

  • 宏任务:包括整体代码script,setTimeout,setInterval,setImmediate(Node.js 环境)。
  • 微任务:包括Promise,process.nextTick(Node.js 环境),MutationObserver(浏览器中的API)。

八 什么是执行栈

执行栈(调用栈),是一个按照先进后出的方式操作的栈结构,用于存储在代码执行期间创建的所有执行上下文。

九 Node 中的 Event Loop 和浏览器中的有什么区别?process.nextTick 执行顺序?

Node.js 和浏览器中的事件循环有核心的架构差异,主要体现在它们处理异步事件的方式以及各自的微任务和宏任务的调度上。下面详细解释这些差异:

Node.js 中的事件循环

Node.js 的事件循环由 libuv 库实现,它是设计来适应异步 I/O 的需求。Node.js 的事件循环分为几个不同的阶段,每个阶段都有自己的任务队列:

  1. timers 阶段:这一阶段执行 setTimeout 和 setInterval 回调。
  2. I/O callbacks 阶段:处理大部分非定时器的回调,如网络通信、文件操作等。
  3. idle, prepare 阶段:仅内部使用。
  4. poll 阶段:检索新的 I/O 事件; 执行与 I/O 相关的回调(除了关闭回调,定时器和 setImmediate() 之外的几乎所有回调); 节点将在适当的条件下阻塞在这里。
  5. check 阶段:setImmediate() 回调在这里执行。
  6. close callbacks 阶段:例如 socket.on(‘close’, …) 的回调。

浏览器中的事件循环

浏览器的事件循环相对简单,主要是为了处理用户界面事件。它不需要像 Node.js 那样处理大量的异步 I/O 操作。浏览器的事件循环通常包括以下几个部分:

  1. 宏任务队列:包括处理脚本(script)、setTimeout、setInterval、I/O、UI rendering等。
  2. 微任务队列:处理 Promise、MutationObserver。当执行栈为空时,会在下一个宏任务执行前,先执行所有微任务。

process.nextTick 执行顺序

在 Node.js 中,process.nextTick() 不是事件循环的一部分,而是一个独立于事件循环的机制。process.nextTick() 允许用户在当前操作完成后,任何 I/O 事件(包括定时器和 setImmediate)之前,立即执行回调。如果在事件循环各个阶段中多次调用 process.nextTick(),Node.js 将会在进入下一阶段之前立即执行这些回调。

总结

  • Node.js 的事件循环是为了支持高效的异步 I/O 操作而设计的,包含多个阶段和专门的队列。
  • 浏览器 的事件循环主要是为了处理用户界面的响应,有一个相对简单的模型,主要区分宏任务和微任务。
  • process.nextTick() 在 Node.js 中,总是在当前执行栈清空后和任何其他异步事件之前执行,这使其成为触发紧急或必要任务的一种方式。

十 事件触发的过程

事件触发基本遵循以下流程:

  1. 事件监听:首先需要有某种方式(如addEventListener)去监听事件。
  2. 事件触发:当相应的用户操作或浏览器操作(如点击、加载等)发生时,事件被触发。
  3. 事件对象生成:浏览器会生成一个事件对象,该对象包含所有与事件相关的信息。
  4. 事件传播:事件会按照特定的顺序(捕获->目标->冒泡)进行传播。
  5. 事件处理:当事件到达被监听的元素时,对应的处理函数会被调用,事件对象会被传入,以供访问和操作。
  6. 事件结束:一旦所有事件监听器执行完毕,或者事件传播被显式停止(如调用stopPropagation()),事件生命周期结束。

垃圾回收机制

一 V8的垃圾回收机制

V8 引擎是 Google 开发的 JavaScript 引擎,它被广泛应用在 Chrome 浏览器和 Node.js 环境中。V8 的垃圾回收机制是其核心功能之一,主要目的是自动管理内存,即自动分配内存及回收不再使用的内存。V8 的垃圾回收机制主要分为两部分,处理新生代(young generation)和老生代(old generation)对象的回收策略。

1. 新生代内存回收

新生代内存主要存储生命周期较短的小对象。V8 为新生代内存分配了相对较小的空间(在64位系统中通常是 32 MB,在32位系统中通常是 16 MB)。垃圾回收在新生代内存中频繁进行,使用的是 Scavenge 算法,具体实现策略是 Cheney 算法,这是一种典型的复制式垃圾回收技术。

  • Scavenge 算法:在新生代空间中,内存被分为两个等大的部分,一半是对象区(active),另一半是空闲区(inactive)。新分配的对象首先放入对象区,当对象区满时,垃圾回收开始工作。存活的对象会被复制到空闲区,非存活对象则被舍弃。完成复制后,对象区和空闲区的角色互换。

2. 老生代内存回收

老生代内存用于存储生命周期长或体积较大的对象。老生代的内存空间远大于新生代(在64位系统中可达到 1.4 GB)。老生代使用 Mark-Sweep(标记-清除)和 Mark-Compact(标记-压缩)算法。

  • Mark-Sweep(标记-清除):这一阶段,垃圾回收器遍历堆中所有对象,并标记存活的对象。之后,进行一次清扫,回收未被标记的对象所占用的内存。此算法的缺点是可能会导致 “内存碎片”。

  • Mark-Compact(标记-压缩):为了解决内存碎片问题,V8 会周期性地进行标记-压缩回收。在标记阶段之后,存活的对象会被向内存的一端压缩,从而减少碎片,优化内存分配效率。

性能考虑

垃圾回收过程会暂停 JavaScript 的执行(称为 “停顿时间”),这对于需要高性能和实时响应的应用可能产生影响。V8 持续优化垃圾回收算法以减少停顿时间,例如通过增量标记(incremental marking)和延迟清扫(lazy sweeping)等技术。

总之,V8 的垃圾回收机制是一个复杂但高效的内存管理系统,它通过新生代和老生代的不同策略,有效地回收内存,同时尽量减少对应用性能的影响。

二 哪些操作会造成内存泄漏?

内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。在Web应用中,内存泄漏可能导致应用变慢甚至崩溃,特别是在长时间运行的应用中。下面是一些常见的造成内存泄漏的操作:

  1. 全局变量

    • 无意中创建的全局变量。例如,未声明就赋值的变量自动成为全局变量。
  2. 定时器

    • 未被清除的定时器或间隔调用(例如setInterval),特别是那些引用了DOM元素的定时器,可能会阻止这些DOM元素被回收。
  3. 闭包

    • 滥用闭包可能会导致父函数中的变量无法被释放,尤其是在闭包被长时间保持不释放时。
  4. DOM引用

    • 如果JavaScript持续保持对已从DOM中删除的元素的引用,那么这些元素不会被垃圾回收机制回收。
  5. 事件监听器

    • 未被正确移除的事件监听器可以导致内存泄漏,因为它们可能保持对DOM元素的引用,阻止这些元素被回收。
  6. 第三方库

    • 使用的第三方库如果有内存泄漏,也可能影响使用这些库的应用。

了解这些常见的内存泄漏来源并采用适当的策略可以帮助在开发过程中避免内存泄漏,提升应用的性能和稳定性。

相关推荐

  1. 浏览器原理浏览器机制

    2024-04-21 06:34:01       41 阅读
  2. 浏览器原理 浏览器安全

    2024-04-21 06:34:01       41 阅读
  3. 浏览器原理浏览器同源策略

    2024-04-21 06:34:01       32 阅读
  4. 浏览器原理本地存储

    2024-04-21 06:34:01       41 阅读
  5. 浏览器原理---浏览器同源策略

    2024-04-21 06:34:01       32 阅读
  6. 前端开发浏览器垃圾回收机制

    2024-04-21 06:34:01       30 阅读
  7. 浏览器渲染原理

    2024-04-21 06:34:01       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-21 06:34:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-21 06:34:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-21 06:34:01       82 阅读
  4. Python语言-面向对象

    2024-04-21 06:34:01       91 阅读

热门阅读

  1. html5与css3前端学习笔记

    2024-04-21 06:34:01       29 阅读
  2. 分类与预测算法评价的介绍

    2024-04-21 06:34:01       34 阅读
  3. MySQL数据加密,模糊查询

    2024-04-21 06:34:01       31 阅读
  4. 优雅的最大公约数函数

    2024-04-21 06:34:01       33 阅读
  5. C++11统一列表初始化,initializer_list

    2024-04-21 06:34:01       30 阅读
  6. 代码随想录-哈希表 | 242 有效的字母异位词

    2024-04-21 06:34:01       35 阅读
  7. Rust常用特型之TryFrom和TryInto特型

    2024-04-21 06:34:01       35 阅读