第二十三天
(题目来源: 前端每日知识3+1)
Javascript题目
写一个方法判断字符串是否为回文字符串
解题思路
解答过程
function reverseStr(str) {
// let newStr = [...str].reverse().join('')
let newStr = str.split('').reverse().join('')
return str == newStr ? true : false
}
console.log(reverseStr('abcba'));
function reverseStr(str) {
// let n = 0;
// let len = str.length % 2 == 0 ? str.length / 2 : Math.ceil(str.length / 2) // 判断字符长度的奇偶性,从中间分开,奇数则循环它的长度-1/2 向上取整
// for (let i = str.length - 1; i >= len; i--) {
// console.log(`第${n+1}次循环`); // 循环的次数
// if (str[i] !== str[n++]) {
// return false
// }
// }
if (str.length == 1) return true
let len = str.length % 2 == 0 ? str.length / 2 : Math.floor(str.length / 2) // 判断字符长度的奇偶性,从中间分开,奇数则循环它的长度-1/2 向下取整
for (let i = 0; i < len; i++) {
console.log(`第${i + 1}次循环`); // 循环的次数
if (str[i] !== str[str.length - 1 - i]) {
return false
}
}
return true
}
console.log(reverseStr('aababaa')); // true 循环了3次
知识扩展
输入url地址到页面成功渲染中间过程经历了什么
- 大致分为几个过程
- url输入
- DNS解析
- TCP连接
- 发送Http请求
- 服务器处理请求
- 服务器响应请求
- 浏览器渲染页面
- 连接结束
url输入
- url中文名
统一资源定位符
(uniform resource locator), 主要组成部分:protocol(协议
), hostname(主机名
), port(端口号
), params(参数
), query(查询
), fragement(信息片段
)
DNS解析
- 主要功能就是实现ip地址的转换, 它是域名和ip地址相互映射的分布式数据库
- 查询方式有两种: 递归查询, 迭代查询
- DNS空间的组织方式:
.
根域.com
顶级域mr90.top
第二层域u.mr90.top
子域名h1.u.mr90.top
主机名 - DNS优化: 存在着多级缓冲, 浏览器缓冲, 系统缓冲, 路由器缓冲, IPS服务器缓冲, 根域名服务器缓冲, 顶级域名服务器缓冲, 主域名服务器缓冲; DNS负载均衡 使用多个IP地址, 针对不同端的请求, 服务器返回的解析结果也不同
TCP连接
SYN(synchronous建立联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
期间经历了三次握手
- 第一次握手:client向server发送请求,将标志位SYN置为一随机生成一个seq=x,客户端进入了SYN_SEND状态
- 第二次握手:server在接受到请求后,将server端的标志位SYN和ACK都设置为1,
ack=x+1
也就是客户端第一次握手生成的seq
值,服务端然后在随机的生成一个seq值y
,并将确认信息向client端发送,此时服务端进入SYN_RCVD状态 - 第三次握手:客户端接收到请求后先判断服务端发送的标志位
ack
的值是否等于x+1
,服务端检查客户端发来的标志位ack
是否等于y+1
,和ACK的值是否等于1;如果都相同,客户端和服务器都进入established
状态
为什么是三次握手而不是两次
- TCP/IP 协议是传输层的一个面向连接的安全可靠的一个传输协议, 三次握手的机制是为了保证能建立一个安全可靠的连接, 那么第一次握手是由客户端发起, 客户端会向服务端发送一个报文, 在报文里面: SYN标志位置为1, 表示发起新的连接. 当服务端收到这个报文之后就知道客户端要和我建立一个新的连接, 于是服务端就向客户端发送一个确认消息包, 在这个消息包里面:ack标志位置为1, 表示确认客户端发起的第一次连接请求. 以上两次握手之后, 对于客户端而言: 已经明确了我既能给服务端成功发消息, 也能成功收到服务端的响应. 但是对于服务端而言: 两次握手是不够的, 因为到目前为止, 服务端只知道一件事, 客户端发给我的消息我能收到, 但是我响应给客户端的消息, 客户端能不能收到我是不知道的. 所以, 还需要进行第三次握手, 第三次握手就是当客户端收到服务端发送的确认响应报文之后, 还要继续去给服务端进行回应, 也是一个ack标志位置1的确认消息. 通过以上三次连接, 不管是客户端还是服务端, 都知道我既能给对方发送消息, 也能收到对方的响应. 那么, 这个连接就被安全的建了
发送http请求
- 完整的请求信息主要有三部分: 请求地址(协议), 请求头, 请求正文
- 请求正文和请求头之间是一个空行
服务器处理请求
- 后端在固定的端口接收到请求报文后, 对TCP连接进行处理, 对HTTP协议进行解析 并将报文格式转换成
HTTP Request
对象
服务器响应请求
- 与http请求类似, 也是由三部分组成
状态行
,响应头
,响应正文
浏览器渲染页面
五个部分组成: 根据html解析
DOM树
, 根据css生成css规则树
, 结合DOM树
和css规则树
生成渲染树
, 根据渲染树计算
每一个节点
的信息
(布局), 根据计算好的信息在绘制
页面
- html解析DOM树: 按照HTML的结构, 采用深度优先遍历的方式构建
DOM树
, 就是构建当前节点的所有子节点, 然后在构建下一个兄弟节点; 当遇到script标签时, 暂停页面的解析, 加载js执行完成后, 再次开始解析HTML构建DOM树 - 根据css生成css规则树: 在解析css规则树时js执行将暂停, 直到css规则树构造完成, 此时页面并未进行渲染
- 生成渲染树: DOM树和css规则树准备完成, 开始构建渲染树
- 计算每一个节点的信息(布局): 通过构建好的渲染树信息, 计算出渲染对象的位置以及尺寸; 如果在此过程中 由于某个部分导致页面布局变化, 则需要执行重排/回流reflow操作
- 绘制页面: 在绘制阶段系统会遍历呈现树, 调用呈现器”paint”方法将内容呈现到屏幕中, 并再此过程中执行
repaint和reflow
操作
连接结束
- TCP四次挥手, 四次挥手即终止TCP连接, 就是指断开一个TCP连接时, 需要客户端和服务端总共发送
4
个包以确认连接的断开. 在socket编程中, 这一过程由客户端或服务端任一方执行close来触发. 由于TCP连接是全双工的, 因此, 每个方向都必须要单独进行关闭, 这一原则是当一方完成数据发送任务后, 发送一个FIN来终止这一方向的连接, 收到一个FIN只是意味着这一方向上没有数据流动了, 即不会再收到数据了, 但是在这个TCP连接上仍然能够发送数据, 直到这一方向也发送了FIN. 首先进行关闭的一方将执行主动关闭, 而另一方则执行被动关闭. - 关闭请求可以是客户端发起也可以是服务器端发起
- 第一次挥手: 由客户端主动发起, 发送标志位FIN=1表示提醒服务器要关闭数据传送了, 发送序列号 随机seq=x, 进入FIN_WAIT_1状态
- 第二次挥手: 由服务端接受到请求报文后, 自动返回一个ACK=1, ack=x+1, 进入CLOSE_WAIT状态, 客户端自动进入FIN_WAIT_2状态
- 第三从挥手: 当服务器确认数据已发送完成 然后向客户端发送FIN报文, 生成随机序列seq=y 服务器端进入LAST_ACK状态.
- 第四次挥手: 客户端接收FIN=1发送ack=y+1后进入TIME_WAIT状态 则可以断开连接, 客户端等待2MSL后没有收到任何的回复说明 服务器端已正常关闭, 客户端也可以关闭了
四次挥手: 四次挥手也是客户端发起的, 客户端会发送一个报文, 报文FIN=1, 当客户端收到这个报文之后, 就知道了客户端想要和我断开连接, 但是此时服务端不一定做好准备, 因为当客户端发起断开连接的报文的时候, 服务端有可能还有未发送完的报文消息需要继续发送, 所以此时服务端只能告诉客户端我知道你要和我断开连接了, 但是我这里可能还没做好准备, 需要等我一下, 等会我会告诉你, 于是, 发完这个消息确认报之后, 稍过片刻之后服务端继续发送一个断开连接的报文, FIN=1, 表明服务端已经做好断开连接的准备, 那么, 当这个消息发给客户端的时候, 客户端同样需要继续发送一个消息确认的报文, 那么通过这四次的相互沟通和连接, 我就知道了, 不管是客户端还是服务端, 都已经做好了断开的准备. 这是我对三次握手四次挥手的理解.