面试题总结 www.nowcoder.com/discuss/501…
事件委托
事件具备传播机制:
- 从最外层向最里层逐一查找 [捕获阶段:分析出路径]
- 把事件源(点击的这个元素)的点击行为触发 [目标阶段]
- 按照捕获阶段分析出来的路径, 从里到外, 把每一个元素的点击行为也触发 [冒泡阶段]
事件和事件绑定:
- 事件是浏览器赋予元素的默认行为
- 事件绑定是给这个行为绑定一个方法
即便没有给body的点击事件绑定方法, 当点击body的时候,其点击行为也会被触发, 只不过啥事都不做而已
阻止事件传播
-
包含传播和冒泡(但是不阻止同级别绑定事件)
e.stopPropagation() -
阻止事件传播, 可以把当前元素绑定的其他方法, 如果还未执行, 也不会接着执行了
e.stopImmediatePropagation()
:
- 利用时间的传播机制, 实现的一套事件绑定处理方案
- 例如, 一个容器中, 有很多元素需要在点击的时候做一些事情
- 传统方案:首先获取需要操作的元素 然后逐一事件绑定
- 事件委托: 只需要给容器做一个事件绑定
点击内部任何元素, 根据事件的冒泡传播机制,都会让容器的点击事件也触发. 这里判断事件源, 做相应处理
:
- 提高JS代码运行性能
- 集中处理逻辑
- 某些需求,必须基于事件委托处理; 例如: 除了点击xxx外, 点击其余的任何东西都固定做一件事.
:
- 当前事件必须支持事件冒泡 传播机制
- mouseenter/mouseleave事件没有事件冒泡传播机制
- 如果单独的事件绑定中, 做了阻止事件传播机制的设定, 事件委托也不会生效
React 合成事件的处理原理
- 绝对不是给当前元素基于addEventListener单独做的事件绑定
- React中的合成事件, 都是基于"事件委托"处理的
- 在React17及以后版本, 都是委托给#root这个容器 [捕获和冒泡都做了委托]
- 在React17以前, 都是委托给#document [只做了冒泡阶段的处理]
- 对于没有实现事件传播机制的事件, 才会单独绑定 [mouseenter]
React JSX元素属性中有 onXXX/onXXXCapture这样的属性, 不会给当前元素做事件绑定, 只是把绑定的方法赋值给元素的相关属性
- onClick 不等于 onclick, 不是DOM0级事件绑定
然后对#root这个容器做了事件绑定 [捕获和冒泡都做了]
- 因为组件所渲染的内容, 都会插入到#root容器中
- 这样点击页面的每一个元素, 都会把#root的点击行为触发
- 而在给#root绑定的方法中, 把之前给元素设置的 onXXX 属性, 在相应阶段执行
ev.stopPropagation(); //合成事件对象中的“阻止事件传播”:阻止原生的事件传播 & 阻止合成事件中的事件传播
ev.nativeEvent.stopPropagation(); //原生事件对象中的“阻止事件传播”:只能阻止原生事件的传播
ev.nativeEvent.stopImmediatePropagation(); //原生事件对象的阻止事件传播,只不过可以阻止#root上其它绑定的方法执行[阻止同级绑定的事件]
从输入URL到页面加载的过程
- 1.浏览器中输入网址
- 2.浏览器查找当前URL是否存在缓存,并检查是否过期
- 如果资源有强缓存,则会直接使用这个缓存的副本,并不再发送请求到浏览器 [通过Expires或Cache-Control字段]
- 强缓存失效, 会使用协商缓存, 浏览器发送HTTP请求包含if-None-Match或if-Modified-Since头部告诉服务器, 服务器返回200或304
- 3.通过DNS解析域名的实际IP地址 [本地缓存中有域名解析结果将跳过]
- 4.与 WEB 服务器建立 TCP 连接 [三次握手]
- 5.若协议是https则会做加密
- 6.浏览器发送HTTP请求获取页面html
- 7.服务器响应html
- 8.浏览器解析 HTML
- 9.浏览器渲染页面
- --根据HTML代码生成DOM tree
- --根据CSS代码生成CSSOM
- --将DOMtree和CSSOM整合行程Render Tree
- --根据Render Tree渲染页面
- --遇到
- --直到把Render Tree 渲染完成
- 10.浏览器解析执行js脚本
- 11.浏览器发起网络请求
- 12.服务器响应ajax请求
- 13.浏览器处理事件循环等异步逻辑
nodejs内存管理和垃圾回收
新生代: 副本整理(Scavenging) -> 堆空间
这个算法主要用于新生代的内存回收。新生代内存被一分为二,一半用来存储对象,一半保持空闲。新创建的对象首先被放在使用区,当使用区快满时,垃圾回收器会标记并复制活着的对象到空闲区,并清除使用区的所有对象,然后交换使用区和空闲区\
如果用到(老生代)会有两个缺点
- 重复的复制存活对象使得效率低下
- 空间资源的浪费
老生代: Mark-Sweep 和 Mark-Compact -> 堆空间
标记清除(Mark-Sweep)
这是V8的主要垃圾回收算法,用于回收堆中的大部分内存。首先,垃圾回收器将标记所有根对象,然后标记这些根对象引用的对象,再标记被引用的对象引用的对象,如此递归下去,形成一个引用链。标记完成后,垃圾回收器将清除所有未被标记的对象,这些未被标记的对象即为垃圾
标记整理(Mark-Compact)
为了解决 Mark-Sweep 算法的内存碎片问题,引入了 Mark-Compact(标记整理算法),其在工作过程中将活着的对象往一端移动,这时内存空间是紧凑的,移动完成之后,直接清理边界之外的内存
内存泄漏
程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
全局变量
未声明的变量或挂在全局 global 下的变量不会自动回收,将会常驻内存直到进程退出才会被释放,除非通过 delete 或 重新赋值为 undefined/null 解决之间的引用关系,才会被回收
闭包
闭包会引用父级函数中的变量,如果闭包得不到释放,闭包引用的父级变量也不会释放从而导致内存泄漏
谨慎将内存作为缓存
缓存中存储的键越多,长期存活的对象也就越多,垃圾回收时将会对这些对对象做无用功.例如你设置一个map对象, 用来存储用户信息, 那么随着用户增多, map对象会持续增长