HTML面试题(二)
前言:
面试题及答案解析,大部分来自网络整理,我自己做了一些简化,内容有很多部分已经重复,解释也有些乱,大家带着自己的思考去看,整理自己的语言,如果想了解的更多,可以搜索一下,前端面试题宝典微信公众号或者查百度,另外如果出现错误请积极指正❤❤❤
1.web worker的了解
以前我们总说,JS是单线程没有多线程,当JS在页面中运行长耗时同步任务的时候就会导致页面假死影响用户体验,从而需要设置把任务放在任务队列中
执行任务队列中的任务也并非多线程进行的,然而现在HTML5提供了我们前端开发这样的能力 - Web Workers API
概述:
web worker 是运行在后台的 js,独立于其他脚本,不会影响页面的性能
并且通过 postMessage 将结果回传到主线程
这样在进行复杂操作的时候,就不会阻塞主线程了
给JS多线程的环境
缺点:
worker一旦被建立,就会一直运行,不会被主线程的活动打断,但是会造成资源的浪费
限制:
- 同源限制 执行的脚本文件必须和主线程的脚本文件同源
- 文件限制 worker线程无法读取本地文件,它所加载的脚本必须来自网络,且需要与主线程的脚本同源
- DOM操作限制 无法读取主线程所在网页的DOM对象,也不能获取
document
、window
等对象,但是可以获取navigator
、location(只读)
、 - 通信限制 worker线程与主线程不在同一个上下文,不能直接通信,需要通过
postMessage
方法来通信。 - 脚本限制 worker线程不能执行
alert
、confirm
,但可以使用XMLHttpRequest
对象发出ajax请求
注意:
- 虽然使用worker线程不会占用主线程,但是启动worker会比较耗费资源
- 主线程中使用XMLHttpRequest在请求过程中浏览器另开了一个异步http请求线程,但是交互过程中还是要消耗主线程资源
实战场景:
- 加密数据
- 预取数据
- 预渲染
- 复杂数据处理
- 预加载图片
2.img的srcset属性的作用
用于浏览器根据宽,高和像素密度(分辨率)来加载相应的图片资源
注意:像素密度描述只对固定宽度图片有效
仅限于图片
<-- 属性格式: 图片地址 高度描述 像素密度描述(分辨率) -->
<img src="small.jpg" srcset="big.jpg 1440w, middle.jpg 800w, small.jpg 1x">
高度为 1440w 时加载big.jpg
高度为 800w 时加载middle.jpg
同的屏幕密度都要设置图片地址,目前的屏幕密度有1x,2x,3x,4x四种,如果每一个图片都设置4张图片,加载就会很慢
<img src="image-128.png"
srcset="image-128.png 128w, image-256.png 256w, image-512.png 512w"
sizes="(max-width: 360px) 340px, 128px" />
srcset指定图片的地址和对应的图片质量
sizes用来设置图片的尺寸零界点
3.label标签有什么用?
label标签来定义表单控制间的关系
当用户选择该标签时,浏览器自动将焦点转到和标签相关的表单控件上
<label for="Name">Number:</label>
<input type='text' name="Name" id="Name"/>
<label>Date:<input type="text" name="B"/></label>
4.js和css是如何影响DOM树构建
CSS不会阻塞DOM的解析,但是会影响JavaScript的运行
JavaScript会阻止DOM树的解析,最终CSS(CSSOM)会影响DOM树的渲染
类型分三种
JavaScript脚本在html页面中
<html>
<body>
<div>1</div>
<script>
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang'
</script>
<div>test</div>
</body>
</html>
当解析到script标签时,HTML解析器暂停工作
JavaScript引擎介入,并执行scirpt标签中的这段脚本
脚本执行完成之后,HTML解析器回复解析过程
解析解析后续的内容,直至生成最终的DOM
html页面中引入javaScript文件
//foo.js
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang'
<html>
<body>
<div>1</div>
<script type="text/javascript" src='foo.js'></script>
<div>test</div>
</body>
</html>
执行到JavaScript标签时,暂停整个DOM的解析
下载JavaScript文件,下载过程会阻塞DOM解析(下载速度受网络环境,文件大小等因素影响)
优化机制:
- 谷歌浏览器做了一个预解析的操作
- 通过CDN加速JavaScirpt文件下载
- 如果JavaSCript文件中没有操作DOM相关代码,就可以将该脚本设置为异步加载
HLMT页面中有css样式
//theme.css
div {color:blue}
<html>
<head>
<style src='theme.css'></style>
</head>
<body>
<div>1</div>
<script>
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang' // 需要 DOM
div1.style.color = 'red' // 需要 CSSOM
</script>
<div>test</div>
</body>
</html>
先等外部的CSS文件下载完成,并解析生成CSSOM对象
再执行JavaScirpt脚本
JavaScirpt引擎解析前是不知道是否存在了CSSOM,所以不管是否操作了都会执行CSS文件下载
再执行脚本
所以说,JavaScript脚本是依赖样式表的
5.DOM树,CSS树,渲染树是什么?
DOM树
DOM是什么?DOM是文档对象模型,是一个树形结构,根节点是Document,用于存储文档中的节点对象。
可以通过DOM访问HTML元素的内容与联系,也可对其进行修改
CSS树
CSS树,又称CSSOM(CSS Object Model)是一个树形的文档结构,以树存储了各个选择器的映射以及相关样式属性,根节点是html
渲染树
构造DOM树,CSSOM树的时候也在同步构造渲染树(Render Tree),渲染树由DOM和CSSOM结合而成,通过DOM中的可视节点构造,并同时包含CSSOM对应的样式信息。渲染树构造完毕后将在屏幕上进行布局和绘制。
6.CSSOM树和DOM树是同时解析的吗?
浏览器会下载HTML解析页面生成DOM树
遇到CSS标签就开始解析CSS
这个过程不会阻塞
但是如果遇到JS脚本,此时假如CSSOM还没有构建完
需要等待CSSOM构建完
再去执行JS脚本,然后再执行DOM解析
此时会阻塞
7.如何实现浏览器内多个标签页之间的通信?
Broadcast Channel
顾名思义,“广播频道”,官方文档里的解释为“用于同源不同页面之间完成通信的功能”,在其中某个页面发送的消息会被其他页面监听到。
注意“同源”二字,该方法无法完成跨域的数据传输。
localStorage
localStorage是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信(ps:session是会话级的存储空间,每个标签页都是单独的)。
SharedWorker
SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
WebSocket通讯
全双工(full-duplex)通信自然可以实现多个标签之间的通信
定时器setInterval+cookie
- 在页面A设置一个使用setInterval定时器不断刷新,检查Cookies的值是否发生变化,如果变化就进行刷新的操作。
- 由于Cookies是在同域可读的,所以在页面B审核的时候改变Cookies的值,页面A自然是可以拿到的。
这样做确实可以实现我想要的功能,但是这样的方法相当浪费资源。虽然在这个性能过盛的时代,浪费不浪费也感觉不出来,但是这种实现方案,确实不够优雅。
postMessage
两个需要交互的tab页面具有依赖关系。
如 A页面中通过JavaScript的window.open打开B页面,或者B页面通过iframe嵌入至A页面,此种情形最简单,可以通过HTML5的 window.postMessage API完成通信,由于postMessage函数是绑定在 window 全局对象下,因此通信的页面中必须有一个页面(如A页面)可以获取另一个页面(如B页面)的window对象,这样才可以完成单向通信;B页面无需获取A页面的window对象,如果需要B页面对A页面的通信,只需要在B页面侦听message事件,获取事件中传递的source对象,该对象即为A页面window对象的引用:
//B页面
window.addEventListner('message',(e)=>{
let {data,source,origin} = e;
source.postMessage('message echo','/');
});
postMessage的第一个参数为消息实体,它是一个结构化对象,即可以通过“JSON.stringify和JSON.parse”函数还原的对象;第二个参数为消息发送范围选择器,设置为“/”意味着只发送消息给同源的页面,设置为“*”则发送全部页面。
8.页面生命周期:DOMContentLoaded,Load,beforeunload,unload
HTML页面的生命周期包含三个重要事件:
- DOMContentLoaded----浏览器已经加载HTML,并构建了DOM树,但像和样式表之类的外部资源可能尚未加载完成
- load----浏览器不仅加载完成了HTML,还加载完成了所有外部资源,图片,样式等
- beforeunload/unload------当用户正在离开页面时
每个事件都是有用的:
- DOMContentLoaded事件-------DOM已经就绪,因此处理程序可以查找DOM节点,并初始化接口
- load事件------------外部资源已经加载完成,样式已被应用,图片大小已知
- beforeunload事件---------用户正在离开,我们可以检查用户是否保存了更改,并询问他是否真的要离开
- unload事件---------用户几乎已经离开,但是我们仍然可以启动一些操作,例如发送统计数据
DomContentLoaded和脚本
当浏览器处理一个HTML文档,并在文档中遇到
因此,DOMContentLoaded肯定在下面的这些脚本执行结束之后发生
此规则有两个例外:
- 具有async特性的脚本不会阻塞DOMContentLoaded
- 使用document.createElement(‘scirpt’)动态生成并添加到网页的脚本也不会阻塞DOMContentLoaded
DomContentLoaded和样式
外部样式表不会影响DOM,因此DOMContentLoaded不会等待它们
但这里有一个陷阱:
如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成
脚本可不知道要不要用到样式相关属性,所以无论用到用不到,它都会等待样式加载完成
前面有一句说的好,脚本是依赖样式表的
浏览器内建的自动填充
Firefox,Chrome和Opera都会在DMOContentLoaded中自动填充表单
例如:
如果一个页面有一个带有登录名和密码的表单,并且浏览器记住了这些值
那么在DOMContentLoaded上,浏览器会尝试自动填充它们(如果用户允许)
因此,如果DOMContentLoaded被需要加载很长时间的脚本延迟触发
那么自动填充也会等待
如果你使用浏览器自动填充
登录和密码字段不会立即自动填充,而是在页面被完全加载钱会延迟填充
这实际上是DOMContentLoaded事件之前的延迟
window.onload
当整个页面,包括样式,图片和其他资源被加载完成时
会触发window对象上的load事件
可以通过onload属性获取此事件
window.onunload
当访问者离开页面时,window对象上的unload事件就会被触发
可以做一些不涉及延迟的操作
如果想通过unload事件,将页面使用数据,保存到服务器上
可以使用特殊的 navigator.sendBeacon(url, data) 方法
不会有延迟,即使浏览器离开页面,也会继续执行
当然,保存完数据后,往往已经离开页面了,所以也无法获取服务器返回的响应
window.onbeforeunload
如果想要离开页面或关闭窗口
beforeunload会进行多次确认
取消确认,浏览器会询问用户是否确定
9.使用input标签上传图片时,咋样触发默认拍照功能?
capture 属性用于指定文件上传控件中媒体拍摄的方式。
可选值:
- user 前置
- environment 后置
- camera 相机
- camcorder 摄像机
- microphone 录音
<input type='file' accept='image/*;' capture='camera'>
10.input上传文件可以同时选择多张吗?怎么设置?
<input type="file" name="files" multiple/>
11.如何禁止input展示输入的历史记录?
在输入input时会提示原来输入过的内容,还会出现下拉的历史记录,禁止这种情况只需在input中加入: autocomplete=“off”
<input type="text" autocomplete="off" />
autocomplete 属性是用来规定输入字段是否启用自动完成的功能。
12.能否使用自闭合script标签引入脚本文件
不能,自闭合标签来自于XML语法,而不是HTML语法
13.iconfont是什么?有什么优缺点?
iconfont是一种字体,但是不包含字母或数字,而是包含符号和字形
优点
- 将任何CSS效果应用于它们
- 是矢量图形,可伸缩
- 只需要发生一个或少量HTTP请求来加载
- 尺寸校,加载速度快
- 在所有浏览器中都得到支持
不足
- 不能用来显示复杂图像
- 通常只限于一种颜色
- 字体图标通常是根据特定的网格设计的
14.页面统计数据中,常用的PV,UV指标分别是什么?
PV(页面访问量)
即页面浏览量或点击量
UV(独立访客)
访问你网站的一台电脑客户端为一个访客
15.什么是DOM和BOM?
DOM
Document,简称文档对象模型
通过创建树来表示文档,描述了处理网页内容的方法和接口
用DOM API 可以轻松地删除,添加和替换节点
BOM
browser object model ,简称浏览器对象模型
描述了与浏览器进行交互的方法和接口
(弹出浏览器窗口,移动,关闭窗口等)
BOM的核心是window,而window对象又具有双重角色
它既是通过js访问浏览器窗口的一个接口,又是一个Global(全局)对象
(是不是js初始化代码都是在 window load 属性中执行的)
这意味着在网页中定义的任何对象,变量和函数,都以window作为器global对象
DOM和BOM的联系和区别
联系
从window.document可以看出
DOM的最根本的对象是BOM的window对象的子对象document
- js是通过访问BOM对象来访问,控制,修改客户端(浏览器)
- 由于BOM的window包含了document,window对象的属性和方法是可以直接使用而且被感知的,因此可以直接使用window对象的document属性,通过document属性就可以访问,检索,修改XHTML文档内容与结构
- 意味document对象又是DOM模型的根节点,可以说BOM包含了DOM(对象)
- 浏览器提供出来给予访问的是BOM对象,从BOM对象再访问到DOM对象,从而js可以操作浏览器以及浏览器读取到文档
- Window对象包含属性:document,location,navigator,screen,history,frames
- Document根节点包含子节点:forms,location,anchors,images,links
(BOM的window对象的子对象是DOM)
区别
DOM描述了处理网页内容的方法和接口
BOM描述了与浏览器进行交互的方法和接口
16.一台设备的dpr,是否可变的?
像素
当设备尺寸相同,但像素变得更密集时,屏幕能显示的画面过渡更细致,图像看起来就更清晰明快
像素的分类
- 物理像素
又称设备像素,指设备屏幕的物理像素,一个屏幕里的物理像素是固定的
- 逻辑像素
又称CSS像素,是为web开发而创造的抽象概念,用于CSS和JavaScript中以【px】描述位置,大小和间距的单位尺寸
DPR
设备像素比
指默认屏幕内容无缩放时,物理像素和逻辑像素的比值
DPR = 物理像素/逻辑像素
再JavaScirpt里可以同过window.deviceRixelRatios获取用户设备的DPR值
17.html和css中的图片加载与渲染规则是什么样的?
概括:
Web页面中不是所有的图片都会加载和渲染!
归纳:
- DOM树和CSSOM树时构建渲染树,如果DOM树节点匹配到CSSOM中的backgorund-image,则会加载背景图片
- 和设置background-image的元素遇到display:none时,图片会加载但不会渲染
- 和设置background-image的元素祖先元素设置display:none时,background-image不会渲染也不会加载,而img和picture引入的图片不会渲染但会加载
- 和background-image引入相同路径相同图片文件名时,图片只会加载一次
- 样式文件中background-image引入的图片,如果匹配不到DOM元素,图片不会加载
- 伪类引入的background-image,比如:hover,只有当伪类被触发时,图片才会加载
18.mete标签中的viewport有什么用
什么是viewport
viewport是用户网页的可视区域
手机浏览器是把页面放在一个虚拟的“窗口”(viewport)中
通常这个虚拟的“窗口”比屏幕宽
这样就不用把每个网页挤到很小的窗口中
用户可以通过平移和缩放来看网页的不同部分
设置Viewport
一个常用的针对移动网页优化过的页面
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- width:控制viewport的大小 特殊值 device-width 为设备的宽度
- height:高度
- initial-scale:初始缩放比例,也即是当页面第一次load的时候缩放比例
- maximum-scale:允许用户缩放到最大的比例
- minimum-scale:允许用户缩放到最小的比例
- user-scalable:用户是否可以手动缩放
19.style标签写再body后于body前有什么区别
页面加载自上而下
当然是先加载样式
渲染机制的区别:
在body前是已经把样式浏览一遍,到了对应标签直接,渲染样式,显示快
在body后,是浏览器已经把标签浏览了,但基于没有样式,显示的不完全,再把body后的样式表,扫描后,在成为真正的样式,会慢,可能会出现FOUC现象(即样式失效导致的页面闪烁问题)
遇到大型网站,效果更差,这都基于浏览器从上而下的浏览机制导致的
20.webSocke如何兼容浏览器
- Adobe Flash Socket
- ActiveX HTMLFile (IE)
- 基于 multipart 编码发送 XHR
- 基于长轮询的 XHR
21.HTML,XML,XHTML的区别
- HTML:超文本标记语言,是语法较为松散的,不严格的Web语言
- XML:可扩展的标记语言,主要用于存储数据和结构,可扩展
- XHTML:可扩展的超文本标记语言,基于XML,作用于HTML类似,但语法更严格
22.标签上title属性与alt属性的区别是什么?
- alt是为了在图片未能正常显示时(屏幕阅读器)给予文字说明,且长度必须少于100个英文字符或者用户必须保证替换文字尽可能的短
- title属性为设置该属性的元素提供建议性的信息 使用title属性提供非本质的额外信息
23.页面导入样式时,使用link和@import有什么区别?
link属于HTML标签,而@import是css提供的
页面被加载时,link会同时被加载,而@import引用的css会等到页面被加载完再加载
@import只在IE5以上才能识别,而link是XHTML标签,无兼容问题
link方式的样式的权重高于@import的权重
24.简单描述从输入网址到页面显示的过程
- DNS解析
- 发起TCP连接
- 发送HTTP请求
- 服务器处理请求并返回HTTP报文
- 浏览器解析渲染页面
- 连接结束
下面我们来看看具体的细节。
DNS解析
DNS解析实际上就是寻找你所需要的资源的过程。假设你输入www.baidu.com,而这个网址并不是百度的真实地址,互联网中每一台机器都有唯一标识的IP地址,这个才是关键,但是它不好记,乱七八糟一串数字谁记得住啊,所以就需要一个网址和IP地址的转换,也就是DNS解析。
DNS解析其实是一个递归的过程。
输入www.google.com网址后,首先在本地的域名服务器中查找,没找到去根域名服务器查找,没有再去com顶级域名服务器查找,,如此的类推下去,直到找到IP地址,然后把它记录在本地,供下次使用。大致过程就是.-> .com ->google.com. -> www.google.com.。 (最后这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上)
DNS优化
既然已经懂得了解析的具体过程,我们可以看到上述一共经过了N个过程,每个过程有一定的消耗和时间的等待,因此我们得想办法解决一下这个问题!
- DNS缓存
DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
- DNS负载均衡
比如访问baidu.com的时候,每次响应的并非是同一个服务器(IP地址不同),一般大公司都有成百上千台服务器来支撑访问。DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡。
发起TCP连接
TCP提供一种可靠的传输,这个过程涉及到三次握手,四次挥手。
三次握手
- 第一次握手:
客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:
服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
四次挥手
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,假设客户端主动关闭,服务器被动关闭。
- 第一次挥手:
客户端发送一个FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可以接受数据。
FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
- 第二次挥手:
服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号seq,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
- 第三次挥手:
服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,我的数据也发送完了,不会再给你发数据了。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
- 第四次挥手:
主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
至此,完成四次挥手。
发送HTTP请求
发送HTTP请求,就是构建HTTP请求报文,并通过TCP协议,发送到服务器指定端口。
请求报文由请求行
,请求报头
,请求正文
组成。
服务器处理请求并返回HTTP报文
对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。这一部分工作一般是由Web服务器去进行,比如Tomcat, Nginx和Apache等Web服务器。
HTTP报文也分成三段:状态码
,响应报头
和响应报文
。
浏览器解析渲染页面
这个图就是Webkit解析渲染页面的过程。
- 解析HTML形成DOM树
- 解析CSS形成CSSOM 树
- 合并DOM树和CSSOM树形成渲染树
- 浏览器开始渲染并绘制页面
后记
后续会继续更新!冲冲✨✨✨