BFC
块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
下列方式会创建块格式化上下文:
- 根元素(
<html>
)
- 浮动元素(
float
值不为none
)
- 绝对定位元素(
position
值为absolute
或fixed
)
- 行内块元素(
display
值为inline-block
)
- 表格单元格(
display
值为table-cell
,HTML表格单元格默认值)
- 表格标题(
display
值为table-caption
,HTML表格标题默认值)
- 匿名表格单元格元素(
display
值为table
、table-row
、table-row-group
、table-header-group
、table-footer-group
(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或inline-table
)
overflow
值不为visible
、clip
的块元素
display
值为flow-root
的元素
contain
值为layout
、content
或paint
的元素
bfc的影响
- 在同一个BFC下,margin-top会发生重叠。(让上下两个元素分别在不同的bfc中)。
- BFC的区域不会与float的元素区域重叠。(浮动元素和非浮动元素重合问题)。
- 计算BFC的高度时,浮动子元素也参与计算。在当前bfc中生效。 (解决父元素高度塌陷问题)。
外边距重叠
处于同一个bfc中两个元素,上下margin会发生重叠,然后取绝对值最大的那个值作为最终的margin。
有三种情况会形成外边距重叠:
- 兄弟元素边距合并。 原因:块级元素的上外边距或下外边距直接接触/相邻时会合并为一个外边距。如果原本二者开始没有接触,那么将不会发生重叠。
- 父子元素边距重叠。 原因:一个盒子如果没有添加
BFC
,那么它的上边距应该和其文档流中的第一个子元素的上边距重叠。
- 空元素边距合并 原因:如果一个块级元素没有任何内容并且设置了
margin-top
和margin-bottom
时会发生margin
合并。
计算机网络模型有哪些?
具体每一层干什么的,传输的数据是什么,有哪些协议?
详解 四层、五层、七层 计算机网络模型对于浏览器来说:
- 应用层:报文。http, dns。
- 传输层:字节流或者报文。tcp, udp。内部有原主机和目的主机监听的进程的端口号。
- 网络层。ip数据报。原主机和目的主机的ip地址。如果数据报想向下传递,就必须知道对应主机的mac地址。这就需要ARP协议来完成了。
- 数据链路层。将数据报封装成帧。并在链路的两个相邻节点间传送帧,每一帧都包含数据和必要的控制信息。
- 物理层。物理层考虑的是如何在各种媒介上传输数据,它定义了与传输媒介相关的接口特性
传输层tcp和udp
建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
tcp
- 面向连接
- 面向字节流
- 可靠传输, TCP 使用超时重传来实现可靠传输。
- 流量控制,通过窗口来控制发送方发送速率,保证接收方来得及接收。
- 网络拥塞控制,根据网络情况来控制发送方发送的速率。
- 点对点的通信方式如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
udp
- 无连接
- 数据报
- 不可靠的
- 广播
- 不具有流量控制和拥塞控制
三次握手四次挥手,为什么是三次握手不能是其他的?
ack: 确定连接,syn: 连接请求。seq:序列号。主要是确认客户端和服务端收发能力是正常的。
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
如果客户端发送的第一个连接请求,超时未到达,那么客户端会重发。但是如果最后这个连接请求又到达了,然后服务端以为是又要建立连接,那么他就返回确认的请求,那么就建立连接了。就会一直等着客户端发送数据,这样server的很多资源就白白浪费掉了。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,自己也未必全部数据都发送给对方了,所以自己可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,自己的ACK和FIN一般都会分开发送。
DNS的解析过程
- 根 DNS 服务器 :返回顶级域 DNS 服务器的 IP 地址
- 顶级域 DNS 服务器:返回权威 DNS 服务器的 IP 地址
- 权威 DNS 服务器 :返回相应主机的 IP 地址 DNS是树状的分布式查询系统。
- 首先查找浏览器中时候缓存的有该域名对应的ip地址。
- 再在本地的hosts文件中查找。
C:\WINDOWS\system32\drivers\etc\hosts
- 再去本地DNS服务器(即你家的网络服务商isp) 以上过程都没有缓存,那么它将请求根DNS服务器。
- 查询根DNS服务器,根据一级域名返回对应的顶级域名服务器的ip地址
- 查询顶级域名服务器,根据二级域名返回对应的权威域名服务器的ip地址
- 根据返回的权威服务器ip地址,然后去请求,即可查询到该域名对应的ip地址。
- 然后将其缓存在本地DNS服务器中,再将其返回给客户端。并且这个过程也可以做负载均衡。根据服务器的压力,我们来决定返回那个服务器的ip地址。因为一个域名可以被映射出多个ip地址。
还有一个迭代解析的过程
本地DNS服务器不是自己向其他DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端DNS程序,客户端DNS程序再继续向这些DNS服务器进行查询,直到得到查询结果为止。
进程与线程的区别
线程是不能单独存在的,它是由进程来启动和管理的。
一个进程就是一个程序的运行实例。详细解释就是,启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程。
- 进程中的任意一线程执行出错,都会导致整个进程的崩溃。
- 线程之间共享进程中的数据。
- 当一个进程关闭之后,操作系统会回收进程所占用的内存。
- 进程之间的内容相互隔离。
栈和堆
在 Chrome 中,只要打开一个渲染进程,渲染进程便会初始化 V8,同时初始化堆空间和栈空间。
栈
栈空间主要是用来管理 JavaScript 函数调用的,栈是内存中连续的一块空间,同时栈结构是“先进后出”的策略。在函数调用过程中,涉及到上下文相关的内容都会存放在栈上,比如原生类型、引用到的对象的地址、函数的执行状态、this 值等都会存在在栈上。当一个函数执行结束,那么该函数的执行上下文便会被销毁掉。
栈空间的最大的特点是空间连续,所以在栈中每个元素的地址都是固定的,因此栈空间的查找效率非常高,但是通常在内存中,很难分配到一块很大的连续空间,因此,V8 对栈空间的大小做了限制,如果函数调用层过深,那么 V8 就有可能抛出栈溢出的错误。
如果有一些占用内存比较大的数据,或者不需要存储在连续空间中的数据,使用栈空间就显得不是太合适了,所以 V8 又使用了堆空间。
堆
堆空间是一种树形的存储结构,用来存储对象类型的离散的数据。
和栈空间不同,存放在堆空间中的数据是不要求连续存放的,从堆上分配内存块没有固定模式的,你可以在任何时候分配和释放它。
异步操作有了解过吗
- promise
- 回调函数
- async await
- 定时器
具体说说事件循环的过程,微任务宏任务有哪些
由于js是单线程的,如果一个事件执行时间过久,那么将会导致线程阻塞。所以为了避免这种事情的发生,浏览器维护了一个消息队列。将异步任务在交给对应的线程或者进程处理完毕后,然后将结果封装成一个函数在传入到这个消息队列中。
比如setTimeout,先让其进入浏览器维护的了一个队列延迟队列中,等到可以触发执行后,然后将其加入到消息队列中,再比如XMLHttpRequest,他会交给浏览器的网络进程处理,处理完毕后,交给浏览器的IO线程,然后将其加入消息队列进行等待调用。
当js执行完主线程的任务后,就回去查看消息队列中是否有任务,需要被调度。就这样一直循环着。
为什么会分为宏任务和微任务呢?
因为宏任务的时间粒度特别大,对于一些时间精度要求特别高的任务来说,不能够满足。
宏任务
- setTimeout
- setInterval
- DOM监听
- UI Rendering等
- XMLHttpRequest 微任务
- queueMicrotask
- MutationObserver
- promise.then
缓存机制
浏览器的缓存机制。
记住是个几个字段
- expires: JMP格式
- cache-control: max-age单位s。还有很多字段值。
- etag / if-none-match
- last-modified / if-modified-since具体请查看这里
手写居中垂直居中
知道元素宽高
- position: absolute + 四个偏移量为0 + margin: auto;
- position: absolute + margin负值 + top + left; 宽高未知
- position: absolute + top + left + translate(-50%);
- flex
- grid
- line-height == height + text-align: center;
求一个字符串的最长无重复的子串
// 实现思路:将字符串元素循环放入到数组中,判断是否有存在的元素,然后删除存在元素之前的全部元素。每次循环都要统计一下数组中的长度,直到最后。 function notRepeatStr(str) { let arr = []; let max = 0; // let resArr = []; for(let i = 0; i < str.length; i++) { if(arr.includes(str[i])) { // 数组中存在,将其前面的元素都删除。 arr.splice(0, arr.indexOf(str[i]) + 1); } // 数组中不存在 arr.push(str[i]); max = Math.max(arr.length, max); } return arr.join(""); }