前端面试拼图-原理源码

摘要:最近,看了下慕课2周刷完n道面试题,记录下...

1. JS内存泄漏如何检测?场景有哪些?

1.1 垃圾回收 GC

        垃圾回收是一种自动管理内存的机制,它负责在运行时跟踪内存的分配和使用情况,并在不再需要的对象上进行自动内存释放,常用的垃圾回收算法:

        标记清除 (Mark-and-Sweep):最常用的垃圾回收算法,垃圾回收器会从根对象(如全局对象、调用栈)出发,标记所有可以访问到的对象,扫描整个堆内存,清除那些未被标记的对象;

        引用计数 (Reference Counting):通过记录对象的引用次数来判断对象是否可达。当对象的引用次数为零时,该对象被视为垃圾并进行回收。引用计数算法的缺点是难以解决循环引用问题。

JS闭包属于内存泄漏吗?

        内存泄漏是指不再需要的对象(非预期的对象)仍然占用内存,导致系统资源浪费和性能下降。严格意义上说闭包并不算内存泄漏,使用闭包是预期相关对象会继续存在在内存中,闭包的数据不能被垃圾回收更合适,因为它依然保持对外部变量的引用。

1.2 JS内存泄漏如何检测

        主要有如下途径:

  • 利用浏览器开发者工具,如Chrome DevTools包含 Memory 面板,可以监控内存使用情况、快照内存状态、查看对象分配情况等;
  • 借助的第三方工具,如 Heap Profiler 工具可以捕获 JavaScript 堆栈中的快照,并分析对象的分配情况、引用关系等,从而发现潜在的内存泄漏问题;
  • 当然也可以在开发过程中手动检测,避免导内存泄漏的情况出现,例如监听时间处理函数未处理、循环引用的存在等。
1.3 至于内存泄漏的场景(Vue为例

        被全局变量、函数引用,组件销毁时未清除

        被全局事件、定时器引用,组件销毁时未清除

        被自定义事件引用,组件销毁时未清除

扩展:WeakMap WeakSet

        WeakMap和WeakSet是JavaScript的内置对象,它们提供了一种存储对象的弱引用的机制,被广泛用于解决内存泄漏和垃圾回收的问题。他们的特点类似:

WeakMap:

  • 一种键值对的集合,其中键必须是对象,值可以是任意类型。键是对象的弱引用,即当对象没有其他引用时,垃圾回收机制可以自动清理该键值对(Vue 3的响应系统中也是用了WeakMap这一特性避免内存泄漏);
  • 没有提供遍历方法,也不能获取其大小或键列表;
  • 由于键是弱引用,所以 WeakMap 是不可迭代的,也不支持常规的对象方法,如 size、forEach 等;
  • 主要用于存储额外的数据或元数据,这些数据与对象的生命周期相关,当对象被销毁时,与之关联的额外数据也会被自动清除。

WeakSet:

  • 一种存储对象的集合,其中的对象是弱引用,同样在没有其他引用时,垃圾回收机制可以自动清除对象。 只能存储对象,不能存储原始值;
  • 不可迭代,也没有提供查询大小、遍历等功能;
  • 主要用于存储一组对象,并且需要确保这些对象不会产生内存泄漏;
  • 与 Set 不同,WeakSet 中的对象是弱引用,因此它们不会阻止垃圾回收器销毁这些对象。

2. 浏览器和node.js的事件循环有什么区别?

2.1 浏览器事件循环

        JS是单线程的(无论浏览器还是nodejs),浏览前中JS执行和DOM渲染共用一个线程,这就需要使用异步编程模型,实现非阻塞的操作,提高程序的性能和响应速度。这就需要使用事件循环机制来处理异步操作,这些异步任务又被分为宏任务和微任务。

        宏任务是一个独立的、完整的任务单元,比如setTimeout SetInterval 网络请求

        微任务通常是一些更小粒度的任务,如Promise async/await

        微任务会被插入到微任务队列(microtask queue)中,在每个宏任务执行完成后,事件循环会检查微任务队列,然后依次执行微任务,直到微任务队列为空

console.log('start')
setTimeout(() => {
  console.log('timeout')
})
Promise.resolve().then(() => {
  console.log('promise then')
})
console.log('end')
// start
// end
// promise then
// timeout

// 微任务在页面渲染前触发,宏任务是在页面渲染之后触发
const p = document.createElement('p')
p.innerHTML = 'new paragraph'
document.body.appendChild(p)
const list = document.getElementsByTagName('p')
console.log('length----', list.length)

console.log('start')
setTimeout(() => {      // 渲染之后触发
  const list = document.getElementsByTagName('p')
  console.log('length on timeout----', list.length)
  alert('阻塞 Timeout')
})
// DOM 渲染
Promise.resolve().then(() => {  // 渲染前触发
  const list = document.getElementsByTagName('p')
  console.log('length on promise.then----', list.length)
  alert('阻塞 promise')
})
console.log('end')
// length---- 67
// start
// end
// length on promise.then---- 67
// length on timeout---- 67

        参考下图,浏览器事件循环机制首先执行左上角的同步代码,遇到异步任务会放入Callback Queue(现在已经分为Macro Queue 和Micro Queue)中,等同步代码执行完成之后,通过Event Loop机制执行队列中的任务

2.2 Node.js事件循环

        Nodejs同样使用ES语法,也是单线程,也需要异步;异步任务也分为:宏任务 + 微任务

        Node.js中事件循环实现是依靠libuv 引擎事件循环中表现得状态与浏览器大致相同。Node.js事件循环的大致执行流程也是先执行同步代码,再执行微任务(process.nextTick),按顺序执行6个类型的宏任务(每当开始之前都执行当前的微任务)

        但是,Node.js的宏任务和微任务,分不同类型,有不同的优先级

        Node.js中宏任务的类型和优先级(由高到低):

  • Timers - setTimout setInterval
  • I/O callbacks - 处理网络、流、TCP的错误回调(执行延迟到下一个循环迭代的I/O回调)
  • Idle,prepare - 闲置状态(Node.js内部使用)
  • Poll轮询 - 执行poll中的I/O队列
  • Check检查 - 存储setImmediate回调
  • Close callbacks - 关闭回调,如socket.on('clos')

        Node.js 微任务类型和优先级:

        包括: Promise,async/await,process.nextTick,其中process.nextTick优先级最高

        总之,在一次事件循环中,先执行当前执行栈中的代码,然后检查是否有微任务需要执行,如果有,则依次执行微任务,直到微任务队列为空;接着从宏任务队列中提取下一个宏任务进行执行。这样的设计保证了微任务能够在宏任务执行结束之后立即得到执行,从而更及时地处理异步操作的结果。

注:

        MDN上最新描述已经不再使用宏任务,沿用它是为了更容易理解

在 JavaScript 中通过 queueMicrotask() 使用微任务 - Web API 接口参考 | MDN一个微任务(microtask)就是一个简短的函数,当创建该微任务的函数执行之后,并且只有当 Javascript 调用栈为空,而控制权尚未返还给被用户代理用来驱动脚本执行环境的事件循环之前,该微任务才会被执行。事件循环既可能是浏览器的主事件循环也可能是被一个 web worker 所驱动的事件循环。这使得给定的函数在没有其他脚本执行干扰的情况下运行,也保证了微任务能在用户代理有机会对该微任务带来的行为做出反应之前运行。icon-default.png?t=N7T8https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_DOM_API/Microtask_guide

        Node.js新版本,推荐使用setImmediate代替process.nextTick。

3. 遍历数组,for和forEach那个更快?

        先上代码验证下,结论是用for通常会比forEach更快

const arr = []
for(let i = 0; i < 100*10000 ; i++) {
  arr.push(i)
}
const length = arr.length

console.time('for')
let n1 = 0
for (let i = 0; i < length; i++) {
  n1++
}
console.timeEnd('for')  // 3.838134765625 ms

console.time('forEach')
let n2 = 0
arr.forEach(() => n2++) 
console.timeEnd('forEach')  // 14.0830078125 ms

        forEach每次都要创建一个函数来调用(函数需要对立的作用域,会有额外的性能开销),而for不会创建函数。

        除此之外,使用for的优点还有:

  • 更多控制:使用for循环可以更灵活地控制循环过程,可以通过控制索引来实现跳过、中断、反向等操作。
  • 可中断性:for循环可以通过break语句或return语句随时中断循环,而forEach方法不支持中断循环,只能通过抛出异常来模拟中断。 虽然for循环在性能上可能更快,但在某些情况下,使用forEach方法可能更具可读性和简洁性

3. 虚拟DOM(vdom)真的很快吗?

        虚拟DOM(virtual dom) 一种用于简化 UI 更新和渲染逻辑的技术, 主要优点在于简化了对真实 DOM 的频繁操作。我们知道Vue React等框架的核心价值在于实现了数据视图分离,数据驱动视图。这样前端程序员coding实只关注业务数据,而不用再关心DOM变化,它们实现数据驱动视图的技术方案就是vdom。

        实际上,vdom并不快,JS直接操作DOM才是最快的;但是"数据驱动视图"需要合适的技术方案,不能全部DOM重建;vdom就是目前最合适的技术方案(并不是因为它快,而是合适)。

扩展:svelte框架就不用vdom

5. Node.js如何开启多进程?进程如何通讯?

        进程(Process) VS 线程 (Thread)

        进程,OS进行资源分配和调度的最小单位,有独立的内存空间

        线程,OS进行运算调度的最小单位,共享进程内存空间

        JS是单线程的,但是可以开启多个进程执行,如WebWorker

        为何需要多进程?

        多核CPU,更适合处理多进程

        内存较大,多个进程才能更好的利用(单进程有内存上限,一般2G左右)

        总之,"压榨"机器资源,更快,更节省

        通过child_process.fork开启子进程

/**
* 主进程
*/
const http = require('http')
const fork = require('child_process').fork

const server = http.createServer(() => {
  if(req.url === '/get-sum') {
    console.info('主进程 id', process.pid)
    // 开启子进程
    const computeProcess = fork('./computer.js')
    computeProcess.send('开始计算')
    computeProcess.on('message', data => {
      console.info('主进程接收到信息:', data)
      res.end('sum is ' + data)
    })
    computeProcess.on('close', data => {
      console.info('主进程因报错而退出')
      computeProcess.kill()
      res.end('error')
    })
  }

})
server.listen(3000, () => {
  console.info('localhost: 3000')
})

/**
* computed.js 子进程,计算
*/
function getSum() {
  let sum = 0
  for (let i = 0; i <10000; i++) {
    sum += i
  }
  return sum
}
//子进程可以通过这种自定义事件的方式来监听
process.on('message', data => {
  console.log('子进程 id', process.pid)
  console.log('子进程接收到的信息‘, data)
  const sum = getSum()
  // 发送消息给主进程
  process.send(sum)
})

//localhost: 30000
// 主进程 id: 80780
// 子进程 id: 80781
// 子进程接收到的信息: 开始计算
// 主进程接收到的信息: 49995000

未完待续……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/434191.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 开发图形界面程序

用 Python 语言开发图形界面的程序&#xff0c;有2种选择&#xff1a; Tkinter 基于Tk的Python库&#xff0c;这是Python官方采用的标准库&#xff0c;优点是作为Python标准库、稳定、发布程序较小&#xff0c;缺点是控件相对较少。 PySide2/PySide6 基于Qt 的Python库&#x…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:浮层)

设置组件的遮罩文本。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 overlay overlay(value: string | CustomBuilder, options?: { align?: Alignment; offset?: { x?: number; y?: number } })…

6. Gin集成redis

文章目录 一&#xff1a;连接Redis二&#xff1a;基本使用三&#xff1a;字符串四&#xff1a;列表五&#xff1a;哈希六&#xff1a;Set七&#xff1a;管道八、事务九&#xff1a;示例 代码地址&#xff1a;https://gitee.com/lymgoforIT/golang-trick/tree/master/14-go-redi…

跨境电商选品API商品采集API接入指南

选品是每个电商卖家的必经之路&#xff0c;产品的好坏将直接决定店铺的盈利、发展方向。选择合适的产品可以让卖家事半功倍&#xff0c;快速爆单。 用API实现代购系统和1688淘宝等平台的商品信息对接&#xff0c;可以免去很多选品工作。 item_get 获得淘宝商品详情item_get_p…

Maven入门(作用,安装配置,Idea基础maven,Maven依赖,Maven构建项目)【详解】

目录 一. Maven的作用 1.依赖管理 2.统一项目结构 3.项目构建 二.Maven安装配置 1. Maven的仓库类型 2 加载jar的顺序 3. Maven安装配置 4.安装Maven 5.配置仓库 三.idea集成maven 1.给当前project集成maven 2.给新建project集成maven 3.创建maven项目 4.pom…

闫震海:腾讯音乐空间音频技术的发展和应用 | 演讲嘉宾公布

一、3D 音频 3D 音频分论坛将于3月27日同期举办&#xff01; 3D音频技术不仅能够提供更加真实、沉浸的虚拟世界体验&#xff0c;跨越时空的限制&#xff0c;探索未知的世界。同时&#xff0c;提供更加丰富、立体的情感表达和交流方式&#xff0c;让人类能够更加深入地理解彼此&…

Spring——Bean的作用域

bean的作用域 Bean Scope Scope说明singleton&#xff08;默认情况下&#xff09;为每个Spring IoC容器将单个Bean定义的Scope扩大到单个对象实例。prototype将单个Bean定义的Scope扩大到任何数量的对象实例。session将单个Bean定义的Scope扩大到一个HTTP Session 的生命周期…

Linux之cd、pwd、mkdir 命令

cd命令&#xff0c;切换目录 1&#xff09;当Linux终端&#xff08;命令行&#xff09;打开的时候&#xff0c;会默认以用户的HOME目录作为当前的工作目录。 2&#xff09;我们可以通过cd命令&#xff0c;更改当前所在的工作目录。 3&#xff09;cd命令来自英文&#xff1a;C…

LeetCode-第67题-二进制求和

1.题目描述 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 2.样例描述 3.思路描述 将两个二进制字符串转换成整型&#xff0c;然后相加后的整型转为二进制字符串 4.代码展示 class Solution(object):def addBinary(self, a, b):# 将字符串…

11. C语言标准函数库

C语言制定了一组使用方式通用的函数&#xff0c;称为C语言标准函数库&#xff0c;用于实现编程常用功能&#xff0c;标准函数库由编译器系统提供&#xff0c;并按功能分类存储在不同源代码文件中&#xff0c;调用标准库内函数时需要首先使用 #include 连接对应的源代码文件。 【…

操作教程|使用MeterSphere对恒生UFX系统进行压力测试

恒生UFX&#xff08;United Finance Exchange&#xff0c;统一金融交换&#xff09;系统&#xff08;以下简称为“UFX系统”&#xff09;&#xff0c;是一款帮助证券公司统一管理外部接入客户的系统&#xff0c;该系统整体上覆盖了期货、证券、基金、银行、信托、海外业务等各类…

【CSP试题回顾】201604-1-折点计数

CSP-201604-1-折点计数 解题代码 #include <iostream> #include <vector> #include <algorithm> using namespace std;int n, pointSum;int main() {cin >> n;vector<int>myData(n);for (int i 0; i < n; i){cin >> myData[i];}// 统…

LinkedList集合源码分析

LinkedList集合源码分析 文章目录 LinkedList集合源码分析一、字段分析二、构造函数分析三、方法分析四、总结 看到实现了Deque 就要联想到这个数据结构肯定是属于双端队列了。Queue 表示队列&#xff0c;Deque表示双端队列。 一、字段分析 LinkedList 字段很少&#xff0c;就…

Python影像分析-根据卫星图像估算土壤湿度

在这篇文章中,我将讨论用于估计土壤湿度的最流行的模型,称为梯形模型。该模型源自卫星,这些卫星以一致的比例和分辨率提供地表温度和植被指数,例如归一化植被指数 (NDVI)。” 目录 🌟简介📥下载 Sentinel-3 表面温度和 NDVI 图像📉绘制 NDVI 与 LST(梯形空间)的图�…

Python爬虫:设置随机 User-Agent

Python爬虫&#xff1a;设置随机 User-Agent 在Python中编写爬虫时&#xff0c;为了模拟真实用户的行为并防止被服务器识别为爬虫&#xff0c;通常需要设置随机的User-Agent。你可以使用fake-useragent库来实现这一功能。首先&#xff0c;你需要安装fake-useragent库&#xff…

【C++专栏】C++入门 | 命名空间、输入输出、缺省参数

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家 点赞&#x1f44d;收藏⭐评论✍ C入门 | 命名空间、输入输出、缺省参数 文章编号&#xff1a;C入门 / 0…

基于stm32的电压采样与质量检测系统

150基于stm32的电压采样与质量检测系统[proteus仿真] 电压检测系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于stm32的电压采样与质量检测系统 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xf…

【递归搜索回溯专栏】专题一递归:汉诺塔

本专栏内容为&#xff1a;递归&#xff0c;搜索与回溯算法专栏。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;递归搜索回溯专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

java性能调优面试,程序员Java视频

前言 很多人在打算自学Java的时候或许都没有思考过Java的应用方向&#xff0c;市场需要什么样的人才&#xff0c;企业对你有什么要求等等一系列问题&#xff1b;或许你只听说这个行业薪资高…然后懵懵懂懂的上路&#xff0c;不得要害。 对于零基础来学习Java&#xff0c;你或…

Go 简单设计和实现可扩展、高性能的泛型本地缓存

相信大家对于缓存这个词都不陌生&#xff0c;但凡追求高性能的业务场景&#xff0c;一般都会使用缓存&#xff0c;它可以提高数据的检索速度&#xff0c;减少数据库的压力。缓存大体分为两类&#xff1a;本地缓存和分布式缓存&#xff08;如 Redis&#xff09;。本地缓存适用于…
最新文章