输入url浏览器干了什么
在浏览器输入URL回车之后,主要发生以下六个行为:
1、URL解析
2、域名解析
3、tcp连接
4、http请求
5、响应请求
6、页面渲染
1、URL解析
ini
首先判断用户输入的内容是url地址还是待搜索关键字,然后做出响应的操作。
URL定义:统一资源定位符,用于访问互联网资源。
语法规则:scheme :// hostname[:port] / path / [?query]#fragment
http://www.baidu.com:80/info/search?key=搜索
scheme:通信协议,常见的有file(本地文件)、ftp、http、https
hostname: 服务器主机名或者ip, 比如 www.zhihu.com
port: 端口号 (默认端口号为80)
path: 文件资源路径
query: 请求参数 ?与#之前的部分为请求参数部分
fragment:片段, #后面的部分为锚片段,一般锚链接会用到
2、域名解析
markdown
1、搜索浏览器DNS缓存,浏览器缓存会维护一张域名跟ip地址的映射关系表
2、如果没有命中则搜索操作系统的DNS缓存
3、如果还是没有命中,则操作系统将域名发送到本地域名服务器,本地域名服务器通过递归的方式查询自己的DNS缓存,查找
到后,将结果返回
4、若本地域名服务器的DNS缓存也没有命中,则本地域名服务器向上级域名服务器进行迭代查询。
第一步 本地域名服务器先向根域名服务器发起请求,根域名服务器将顶级域名服务的地址返回给本地域名服务器
第二步 本地域名服务器根据顶级域名服务器地址向顶级域名服务器发起请求,然后得到权限域名服务器地址
第三步 本地域名服务器通过权限域名服务器地址向权限域名服务器发起请求,然后得到该域名的ip地址
5、本地域名将IP地址返给操作系统,并且本地域名将该IP缓存起来
6、操作系统将IP返回给浏览器,并将ip缓存起来
7、浏览器得到ip地址,并将ip缓存起来
3、tcp连接
ini
在客户端发送数据给服务端之前,会发起TCP三次握手以同步客服端和服务端的序列号和确认号,并交换TCP窗口大小信息
第一次握手
客户端将报文标志位SYN置位1,并随机产生序列号seq=J,保存在TCP首部的序列号(Sequence Number)字段里,指明连接服务器的端口
并将该数据包发送给服务端,数据包发送完毕,客户端进入SYN_SENT状态,等待服务端确认。
第二次握手
服务端收到数据包后由标志位SYN=1得知客户端想要建立连接,并把报文的标志位SYN和ACK都置为1,ack=seq+1,并随机生成序列号
seq=K,并将数据包发送给客户端确认建立连接请求,数据发送后,服务端进入SYN+RCVD状态
第三次握手
客户端收到数据包,检查ack是否为J+1, ACK是否为1,检查正确,则将标志位ACK置为1, ack=K+1,并将数据发送给服务端,服务端
检查ACK是否为1,ack是否为K+1,检查正确,建立连接成功,此时客户端、服务端都进入ESTABLISHED状态,完成三次握手,客户端和
服务端可以开始传输数据
4、http请求
tcp建立成功之后,客户端发送http请求报文到服务端
http请求报文有四部分组成:请求行、请求头、空行、消息体
ruby
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive
name=Professional%20Ajax&publisher=Wiley
上面抓包的请求报文的例子中:
第一部分:请求行,由请求方法、URL 、协议版本组成.也就是第一行数据(POST / HTTP1.1)
第二部分:请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息 (第二行到第六行)
第三部分:空行,请求头部后面的空行是必须的 (第七行的空行)
第四部分:请求数据也叫主体,可以添加任意的其他数据。(第八行)
5、响应请求
当服务器接收到客户端的请求之后,会进行逻辑处理,处理完之后,会返回给客户端一个http响应数据,
响应数据包括三部分:状态行、响应头、响应正文
5、响应请求
scss
当浏览器接收到服务器的响应数据,会解析html,请求js、css等资源,最后进行页面渲染,呈现给用户。
页面渲染大概分为五步:
(1)根据HTML文件解析出DOM Tree
(2)根据CSS解析出 CSSOM Tree(CSS规则树)
(3)将 DOM Tree 和 CSSOM Tree合并,构建Render tree(渲染树)
(4)reflow(重排):Layout根据Render tree进行节点信息计算
(5)repaint(重绘):Painting根据计算好的信息绘制整个页面
回流 重绘,什么情况下发生,为什么发生,在渲染流程的哪一步
1.回流和重绘基本概念
回流:当render树中的一部分或者全部因为大小边距等问题发生改变而需要重建的过程叫做回流(改变大小)。
重绘:当元素的一部分属性发生变化,如外观背景色不会引起布局变化而需要重新渲染的过程叫做重绘(改变样式)。
注意:回流必将引起重绘,而重绘不一定会引起回流。
2.回流和重绘发生条件
当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:
- 添加或者删除可见的 DOM 元素;
- 元素位置改变;
- 元素尺寸改变------边距、填充、边框、宽度和高度
- 内容改变------比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
- 页面渲染初始化;
- 浏览器窗口尺寸改变------resize 事件发生时;
重绘发生条件:元素的属性或者样式发生变化。
回流的开销较大,如果每个操作都去回流重绘的话,浏览器可能就会受不了。所以很多浏览器都会优化这些操作,浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
虽然有了浏览器的优化,但有时一些代码可能会强制浏览器提前flush队列,这样浏览器的优化可能就起不到作用了。当请求向浏览器请求一些 style 信息的时候,就会让浏览器 flush 队列,比如:
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- width、height
- 请求了 getComputedStyle() 或者 IE 的 currentStyle
3.如何减少回流和重绘
减少回流和重绘其实就是需要减少对 render tree 的操作(合并多次多 DOM 和样式的修改),并减少对一些样式信 息的请求,尽量利用好浏览器的优化策略。
- 添加 css 样式而不是利用js控制样式(我就是想到这种办法解决回流问题的)
- 尽量将需要改变 DOM 的操作一次完成
- 直接改变 className,如果动态改变样式,则使用 cssText(考虑没有优化的浏览器)
- 不要经常访问会引起浏览器 flush 队列的属性,如果你确实要访问,利用缓存
- 让元素脱离动画流,减少回流的 Render Tree 的规模
- 将需要多次重排的元素,position 属性设为 absolute 或 fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位;
- 尽量不要使用表格布局,如果没有定宽表格一列的宽度由最宽的一列决定,那么很可能在最后一行的宽度超出之前的列宽,引起整体回流造成 table 可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。
vue2、3响应式原理的区别,组合式api和选项式api的区别
js
# Vue3.0中的响应式原理
vue2.x的响应式
实现原理:
对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data,'count', {
get() {},
set() {}
})
存在问题:
新增属性、删除属性, 界面不会更新。
直接通过下标修改数组, 界面不会自动更新。
Vue3.0的响应式
实现原理:
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射): 对源对象的属性进行操作
flex 布局
js
flex伸缩布局
flex弹性概念:弹性盒子是一种按行或者按列布局元素的一种布局方式。
它是需要父子盒子嵌套使用的。
作用在父盒子(容器)上的属性有:
flex-direction 改变轴方向
flex-wrap 换行
flex-flow 前两项的简写方式
justify-content 主轴对齐方式
align-items 侧轴对齐方式
align-content
作用在子盒子(子项)上的属性有
order
flex-grow 扩展比例
flex-shrink 收缩比例
flex-basis 指定子项在主轴方向上的初始大小
flex
align-self
防抖、节流
bash
防抖 (Debouncing) 的含义是指在一定时间内,多次触发同一个事件,只执行最后一次操作。
例如,当我们在 搜索框中输入关键词时,输入框会不断触发 oninput 事件,如果每次输入
都去请求服务器获取数据,会造成不 必要的请求浪费。此时就可以使用防抖技术,将一定时
间内的多次触发合并为一次操作,只请求一次服务器数据,减少了请求次数和服务器负载。
(英雄联盟--技能cd 触发完等cd结束才可以触发)
节流 (Throttling) 的含义是指在一定时间内,多次触发同一个事件,只执行第一次操作。
例如,当我们拖动网页上的滚动条时,会不断触发 onscroll 事件,如果每次触发都去计算
滚动距离,会造成浏览器性能下降。此时就可以使用节流技术,将一定时间内的多次触发限
制为一次操作,只计算一次滚动距离,提高了浏览器性能和用户体验。
(英雄联盟--技能回城 打断回城要重新按B键)
防抖 (Debouncing)
scss
function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout)
// 立即执行,此类情况一般用不到
if (immediate) {
const callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) typeof func === 'function' && func()
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(() => {
typeof func === 'function' && func()
}, wait)
}
}
节流 (Throttling)
ini
function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func()
timer = setTimeout(() => {
flag = false
}, wait)
}
} else if (!flag) {
flag = true
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func()
}, wait)
}
}
JavaScript 运行机制 (事件循环)
js
整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为两部分:"同步任务"、"异步任务";
同步任务会直接进入主线程依次执行;
异步任务会再分为宏任务(进入宏任务队列) 和 微任务(进入微任务队列)。
当主线程内的任务执行完毕(主线程为空时),会检查微任务的任务队列,如果有任务,就进入主线程
全部执行,如果没有就从宏任务队列读取下一个宏任务执行;
任务队列 task queue
js中的队列可以叫做任务队列或异步队列,任务队列里存放各种异步操作所注册的回调,里面分为两种任务类型,宏任 务(macroTask)和微任务(microTask)。
宏任务
setInterval()
setTimeout()
setImmediate()
ajax
事件绑定
微任务
new Promise()后的then与catch函数
new MutaionObserver()
process.nextTick(Nodejs)
js
setTimeout(function () {
new Promise(function (resolve, reject) {
console.log('异步宏任务promise');
resolve();
}).then(function () {
console.log('异步微任务then')
})
console.log('异步宏任务');
}, 0)
new Promise(function (resolve, reject) {
console.log('同步宏任务promise');
resolve();
}).then(function () {
console.log('同步微任务then')
})
你的答案是什么呢是不是和我一样呢
js
同步宏任务promise
同步微任务then
异步宏任务promise
异步宏任务
- 手写反转链表
js
// 虚拟结点法
public static ListNode reverseList(ListNode head) {
ListNode ans = new ListNode(-1);
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = ans.next;
ans.next = cur;
cur = next;
}
return ans.next;
}