经典HTML前端面试题总结
- 1. 1简述一下你对 HTML 语义化的理解?.
- 1.2 标签上 title 与 alt 属性的区别是什么?
- 1.3 iframe的优缺点?
- 1.4 href 与 src?
- 1.5 HTML、XHTML、XML有什么区别
- 1.6 知道img的srcset的作用是什么?
- 1.7 link和@import的区别?
- 1.8 谈谈对BFC的理解 是什么?
- 1.9 html5有哪些新特性,移除了哪些元素?如何处理HTML5新标签的浏览器谦容问题?如何区分HTML和HTML5?
- 1.10 浏览器的内核分别是什么?经常遇到的浏览器的谦容性有哪些?原因,解决方法是什么,常用hack的技巧?
- 1.11 html常见兼容性问题?
- 1.12 什么是外边距重叠?重叠的结果是什么?
- 1.13 你能描述一下渐进增强和优雅降级之间的不同吗?
- 1.14 HTML5和css3的新标签
- 1.15 DOCTYPE的作用?严格模式和混杂模式的区别?
- 1.16 说一下HTML5的离线存储?
- 1.17 说一下怎么做好seo?
- 1.18 说一下drag api?
- 1.19 说一下canvas和svg的区别?
- 1.20 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?行内元素和块级元素有什么区别?
- 1.21 说说你对 SSG 的理解
- 1.22 说一下web worker?
- 1.23 说一下img的srcset作用?alt和title的区别?
- 1.24 说说你对 Dom 树的理解
- 什么是 DOM
- DOM树如何生成
- JavaScript影响DOM的生成
- 1.25 Node 和 Element 是什么关系?
- 1.26 导致页面加载白屏时间长的原因有哪些,怎么进行优化?
- 一、白屏时间
- 二、白屏时间的重要性
- 三、白屏的过程
- 四、白屏-性能优化
- 1. DNS解析优化
- 2. TCP网络链路优化
- 3. 服务端处理优化
- 4. 浏览器下载、解析、渲染页面优化
- 1.27 渐进式jpg有了解过吗?
- 1.28 怎么实现“点击回到顶部”的功能?
- 1、锚点
- 2、scrollTop
- 3、scrollTo
- 4、scrollBy()
- 5、scrollIntoView()
- 1.29 如何实现SEO优化
- 一、内部优化
- 二、外部优化
- 1.30 SEO是什么?
- 1.31 DNS 预解析是什么?怎么实现?
- DNS优化
- 什么是dns-prefetch?
- 为什么要用dns-prefetch?
- dns-prefetch背后原理
- 浏览器DNS缓存与dns-prefetch
- 浏览器与系统DNS缓存时间
- `dns-prefetch`缺点
- 最佳实践
- 1.32 indexDB怎么使用
- 1.33 HTML5 有哪些 drag 相关的 API ?
- 1.34 浏览器乱码的原因是什么?如何解决?
- 1.35 js和css是如何影响DOM树构建的?
- JavaScript脚本在html页面中
- html页面中引入javaScript文件
- html页面中有css样式
- 1.36 表单中readonly和disabled的区别
- 1.37 主流浏览器及内核
- 1.38 说说你对以下几个页面生命周期事件的理解:DOMContentLoaded,load,beforeunload,unload
- DOMContentLoaded 和脚本
- DOMContentLoaded 和样式
- 浏览器内建的自动填充
- window.onload
- window.onunload
- window.onbeforeunload
- 总结
- 1.39 使用input标签上传图片时,怎样触发默认拍照功能?
- 给input上传多张照片
- 1.40 如何禁止input展示输入的历史记录?
- 1.41 iconfont是什么?有什么优缺点?
- 什么是 IconFont
- 优点
- 不足
- 1.42 页面统计数据中,常用的 PV、UV 指标分别是什么?
- PV(页面访问量)
- UV(独立访客)
- 1.43 一台设备的dpr,是否是可变的?
- 1.44 html和css中的图片加载与渲染规则是什么样的?
- 1.45 mete标签中的viewport 有什么用?
- 什么是 Viewport?
- 设置 Viewport
- 1.46 前端该如何选择图片的格式
- 位图
- 矢量图
- 图片的压缩类型
- 无压缩
- 有损压缩
- 无损压缩
- 图片位数
- 常见的图片的格式
- GIF
- JPEG/JPG
- 渐进式jpeg(progressive jpeg)
- PNG
- APNG
- WEBP
- SVG
- 如何选择图片的格式
1. 1简述一下你对 HTML 语义化的理解?.
- 用正确的标签做正确的事情。
- html 语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;即使在没有样>式 CSS 情况下也以一种文档格式显示,并且是容易阅读的;
- 搜索引擎的爬虫也依赖于 HTML 标记来确定上下文和各个关键字的权重,利于 SEO;
- 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
1.2 标签上 title 与 alt 属性的区别是什么?
alt 是给搜索引擎识别,在图像无法显示时的替代文本;
title 是关于元素的注释信息,主要是给用户解读。
当鼠标放到文字或是图片上时有 title 文字显示。(因为 IE 不标准)在 IE 浏览器中 alt 起到了 title 的作用,变成文字提示。
在定义 img 对象时,将 alt 和 title 属性写全,可以保证在各种浏览器中都能正常使用。
alt 是给搜索引擎识别,在图像无法显示时的替代文本;
title 是关于元素的注释信息,主要是给用户解读。
当鼠标放到文字或是图片上时有 title 文字显示。(因为 IE 不标准)在 IE 浏览器中 alt 起到了 title 的作用,变成文字提示。
在定义 img 对象时,将 alt 和 title 属性写全,可以保证在各种浏览器中都能正常使用。
1.3 iframe的优缺点?
优点:
- 解决加载缓慢的第三方内容如图标和广告等的加载问题
- Security sandbox
- 并行加载脚本
缺点:
- iframe会阻塞主页面的Onload事件
- 即时内容为空,加载也需要时间
- 没有语意
1.4 href 与 src?
- href (Hypertext Reference)指定网络资源的位置,从而在当前元素或者当前文档和由当前属性定义的需要的锚点或资源之间定义一个链接或者关系。(目的不是为了引用资源,而是为了建立联系,让当前标签能够链接到目标地址。)
- src source(缩写),指向外部资源的位置,指向的内容将会应用到文档中当前标签所在位置。
- href与src的区别
- 1、请求资源类型不同:href 指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的联系。在请求 src 资源时会将其指向的资源下载并应用到文档中,比如 JavaScript 脚本,img 图片;
- 2、作用结果不同:href 用于在当前文档和引用资源之间确立联系;src 用于替换当前内容;
- 3、浏览器解析方式不同:当浏览器解析到src ,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等也如此,类似于将所指向资源应用到当前内容。这也是为什么建议把 js 脚本放在底部而不是头部的原因。
1.5 HTML、XHTML、XML有什么区别
- HTML(超文本标记语言): 在html4.0之前HTML先有实现再有标准,导致HTML非常混乱和松散
- XML(可扩展标记语言): 主要用于存储数据和结构,可扩展,大家熟悉的JSON也是相似的作用,但是更加轻量高效,所以XML现在市场越来越小了
- XHTML(可扩展超文本标记语言): 基于上面两者而来,W3C为了解决HTML混乱问题而生,并基于此诞生了HTML5,开头加入
<!DOCTYPE html>
的做法因此而来,如果不加就是兼容混乱的HTML,加了就是标准模式。
1.6 知道img的srcset的作用是什么?
可以设计响应式图片,我们可以使用两个新的属性srcset 和 sizes来提供更多额外的资源图像和提示,帮助浏览器选择正确的一个资源。
srcset 定义了我们允许浏览器选择的图像集,以及每个图像的大小。
sizes 定义了一组媒体条件(例如屏幕宽度)并且指明当某些媒体条件为真时,什么样的图片尺寸是最佳选择。
所以,有了这些属性,浏览器会:
- 查看设备宽度
- 检查 sizes 列表中哪个媒体条件是第一个为真
- 查看给予该媒体查询的槽大小
- 加载 srcset 列表中引用的最接近所选的槽大小的图像
srcset提供了根据屏幕条件选取图片的能力
1.7 link和@import的区别?
- link属于XHTML标签,而@import是CSS提供的。
- 页面被加载时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载。
- import只在IE 5以上才能识别,而link是XHTML标签,无兼容问题。
- link方式的样式权重高于@import的权重。
- 使用dom控制样式时的差别。当使用javascript控制dom去改变样式的时候,只能使用link标签,因为@import不是dom可以控制的。
1.8 谈谈对BFC的理解 是什么?
书面解释:BFC(Block Formatting Context)这几个英文拆解
- Block: Block在这里可以理解为Block-level Box,指的是块级盒子的标准
- Formatting context:块级上下文格式化,它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用
BFC是指一个独立的渲染区域,只有Block-level Box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干.
它的作用是在一块独立的区域,让处于BFC内部的元素与外部的元素互相隔离.
如何形成?
BFC触发条件:
- 根元素,即HTML元素
- position: fixed/absolute
- float 不为none
- overflow不为visible
- display的值为inline-block、table-cell、table-caption
- 作用是什么?
- 防止margin发生重叠
- 两栏布局,防止文字环绕等
- 防止元素塌陷
1.9 html5有哪些新特性,移除了哪些元素?如何处理HTML5新标签的浏览器谦容问题?如何区分HTML和HTML5?
* HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
* 绘画 canvas
用于媒介回放的 video 和 audio 元素
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 的数据在浏览器关闭后自动删除
语意化更好的内容元素,比如 article、footer、header、nav、section
表单控件,calendar、date、time、email、url、search
新的技术webworker, websockt, Geolocation
* 移除的元素
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
支持HTML5新标签:
* IE8/IE7/IE6支持通过document.createElement方法产生的标签,
可以利用这一特性让这些浏览器支持HTML5新标签,
浏览器支持新标签后,还需要添加标签默认的样式:
* 当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
1.10 浏览器的内核分别是什么?经常遇到的浏览器的谦容性有哪些?原因,解决方法是什么,常用hack的技巧?
* IE浏览器的内核Trident、 Mozilla的Gecko、google的WebKit、Opera内核Presto;
* png24为的图片在iE6浏览器上出现背景,解决方案是做成PNG8.
* 浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一。
* IE6双边距bug:块属性标签float后,又有横行的margin情况下,在ie6显示margin比设置的大。
浮动ie产生的双倍距离 #box{ float:left; width:10px; margin:0 0 0 100px;}
这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入 ——_display:inline;将其转化为行内属性。(_这个符号只有ie6会识别)
渐进识别的方式,从总体中逐渐排除局部。
首先,巧妙的使用“\9”这一标记,将IE游览器从所有情况中分离出来。
接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。
css
.bb{
background-color:#f1ee18;/所有识别/
.background-color:#00deff\9; /IE6、7、8识别/
+background-color:#a200ff;/IE6、7识别/
_background-color:#1e0bd1;/IE6识别/
}
* IE下,可以使用获取常规属性的方法来获取自定义属性,
也可以使用getAttribute()获取自定义属性;
Firefox下,只能使用getAttribute()获取自定义属性.
解决方法:统一通过getAttribute()获取自定义属性.
* IE下,even对象有x,y属性,但是没有pageX,pageY属性;
Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
* (条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。
* Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序:
L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
1.11 html常见兼容性问题?
1.双边距BUG float引起的 使用display
2.3像素问题 使用float引起的 使用dislpay:inline -3px
3.超链接hover 点击后失效 使用正确的书写顺序 link visited hover active
4.IE z-index问题 给父级添加position:relative
5.Png 透明 使用js代码 改
6.Min-height 最小高度 !Important 解决’
7.select 在ie6下遮盖 使用iframe嵌套
8.为什么没有办法定义1px左右的宽度容器(IE6默认的行高造成的,使用over:hidden,zoom:0.08 line-height:1px)
9.IE5-8不支持opacity,解决办法:
.opacity {
opacity: 0.4
filter: alpha(opacity=60); /* for IE5-7 */
-ms-filter: “progid:DXImageTransform.Microsoft.Alpha(Opacity=60)”; /* for IE 8*/
}
\10. IE6不支持PNG透明背景,解决办法: IE6下使用gif图片
1.12 什么是外边距重叠?重叠的结果是什么?
外边距重叠就是margin-collapse。
在CSS当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。
折叠结果遵循下列计算规则:
两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
两个外边距一正一负时,折叠结果是两者的相加的和。
1.13 你能描述一下渐进增强和优雅降级之间的不同吗?
渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。
“优雅降级”观点
“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。
在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。你可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。
“渐进增强”观点
“渐进增强”观点则认为应关注于内容本身。
内容是我们建立网站的诱因。有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo! 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。
1.14 HTML5和css3的新标签
HTML5: nav, footer, header, section, hgroup, video, time, canvas, audio…CSS3: RGBA, opacity, text-shadow, box-shadow, border-radius, border-image, border-color, transform…;
1.15 DOCTYPE的作用?严格模式和混杂模式的区别?
!DOCTYPE告诉浏览器以HTML5标准解析页面,如果不写,则进入混杂模式
严格模式(标准模式):以w3c标准解析代码
混杂模式(怪异模式):浏览器用自己的方式解析代码,混杂模式通常模拟老式浏览器的行为,以防止老站点无法工作
HTML5 没有 DTD ,因此也就没有严格模式与混杂模式的区别,HTML5 有相对宽松的方法,实现时,已经尽可能大的实现了向后兼容(HTML5 没有严格和混杂之分)。
1.16 说一下HTML5的离线存储?
HTML5的离线存储是一种Web应用程序缓存技术,通过将Web应用程序的资源(如HTML文件、CSS样式表、JavaScript代码和图像等)保存到本地计算机上,可以使Web应用程序离线访问时仍然能够正常工作。离线存储可以提高Web应用程序的性能和可访问性,并提供了一种更加稳定和可靠的方式来提供Web应用程序。
在HTML5中,使用Application Cache API来实现离线存储,通过在HTML文件头部添加一个manifest属性指向一个描述了需要缓存的资源列表的清单文件,即可启用离线存储。一旦Web应用程序被离线缓存,用户可以在没有网络连接的情况下访问该应用程序,而无需从远程服务器下载资源。
尽管离线存储可以提高Web应用程序的性能和可访问性,但开发人员应该注意其缺点。由于离线存储的数据是保存在本地计算机上的,因此如果数据被篡改或损坏,Web应用程序可能会受到安全威胁或无法正常工作。此外,离线存储的数据也可能占用大量的本地存储空间,这可能会影响用户的设备性能。
1.17 说一下怎么做好seo?
- 网站结构优化:要保证网站的结构清晰、简洁,避免使用过多的Flash、JavaScript等对搜索引擎不友好的技术。
- 关键词优化:要根据网站所属的行业、目标用户等因素确定关键词,并将其合理地应用在标题、正文、图片等各个位置,但同时也要避免过度使用关键词,以免被搜索引擎识别为垃圾信息。
- 内容优化:要提供高质量、有价值的内容,吸引用户留下来,增加用户停留时间和页面访问量,同时也可以提升网站的信誉度和排名。
- 外部链接优化:要通过寻找相关的高质量外部链接,来提高网站的权重和排名。
1.18 说一下drag api?
Drag API是一种Web API,可以将拖放功能添加到网页中。它允许用户通过点击和拖动鼠标,将某些元素从一个位置移动到另一个位置。
使用Drag API,开发者可以在网页上实现自定义拖放功能,并对其进行细粒度的控制。例如,可以定义哪些元素可以被拖动,哪些元素可以作为拖放目标,以及如何处理拖放事件等。
Drag API提供了几个主要的接口和事件:
- Draggable:通过将draggable属性设置为true,将一个元素标记为可拖动的。
- Dragstart事件:当用户开始拖动一个元素时触发。
- Dragenter事件:当一个可拖动元素进入一个可以放置的元素区域时触发。
- Dragover事件:当一个可拖动元素在一个可以放置的元素区域内移动时触发。
- Drop事件:当用户松开鼠标,释放一个可拖动元素并将其放置到一个可以放置的元素区域时触发。
- Dragend事件:当用户完成拖动操作后触发。
通过使用Drag API,开发者可以创建各种有趣和交互性强的网页应用程序,例如拖动图片上传、拖动元素排序、拖动图表等。它可以改善用户体验,提高网站的吸引力和互动性。
1.19 说一下canvas和svg的区别?
Canvas 和 SVG 都是 HTML5 提供的常见的绘图技术,但两者的实现原理和应用场景却有很大的区别。
- 实现原理 Canvas 是基于像素的绘图技术,它通过 JavaScript 操纵画布上的像素来进行绘图。在使用 Canvas 绘图时,我们可以获得一个类似于画布的空间,然后在其上利用数组进行像素点的操作和绘制出需要的图案。而 SVG 采用矢量绘图的方式,也就是基于数学公式,将各种图形和元素的形状、大小、位置等属性通过计算机计算后转化为一条条向量路径,最终表现在屏幕上。
- 应用场景 Canvas 更适用于动态展示大量复杂的图形或动画效果,如游戏、数据可视化、海报设计等,因为它能够快速地控制像素点,具备更高的灵活度和交互性。而 SVG 主要用于静态或固定比例的图形绘制,例如图标、标识、矢量地图等,由于其本身是矢量形式的,当缩放或变形后不会失真。此外,SVG 还提供了丰富的交互事件和 CSS 样式支持,对于需要编辑和修改的图形元素而言,使用 SVG 更为方便。
- 性能和可维护性 由于 Canvas 是基于像素操作的,涉及到大量的计算和渲染,因此在处理静态的图形绘制时,相较于 SVG 具备不优秀的性能表现。但对于大型动态图像以及需要实时交互的应用,Canvas 比 SVG 更具优势。由于 SVG 是基于 XML 标记语言来构建图形,因此代码量更多,当 SVG 绘制的图形变得更加复杂时,其代码的可维护性就会降低。
(1)SVG: SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言XML描述的2D图形的语言,SVG基于XML就意味着SVG DOM中的每个元素都是可用的,可以为某个元素附加Javascript事件处理器。在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
其特点如下:
- 不依赖分辨率
- 支持事件处理器
- 最适合带有大型渲染区域的应用程序(比如谷歌地图)
- 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
- 不适合游戏应用
(2)Canvas: Canvas是画布,通过Javascript来绘制2D图形,是逐像素进行渲染的。其位置发生改变,就会重新进行绘制。
其特点如下:
- 依赖分辨率
- 不支持事件处理器
- 弱的文本渲染能力
- 能够以 .png 或 .jpg 格式保存结果图像
- 最适合图像密集型的游戏,其中的许多对象会被频繁重绘
注:矢量图,也称为面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。
综上所述,Canvas 和 SVG 两种技术各自有其适合的应用场景,需要针对具体业务需求进行选择。如果需要展示一些简单的固定图案或数据统计图表等,采用 SVG 更加适合;而如果是要制作一些互动性强的动画、游戏,则使用 Canvas 更为方便有效。
1.20 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?行内元素和块级元素有什么区别?
- 行内元素有:
a b span img input select strong
- 块级元素有:
div ul ol li dl dt dd h1 h2 h3 h4…p
- 空元素:
<br> <hr> <img> <input> <link> <meta>
- 行内元素不可以设置宽高,不独占一行
- 块级元素可以设置宽高,独占一行
1.21 说说你对 SSG 的理解
SSG(Static Site Generation,静态网站生成)是指在构建时预先生成静态页面,并将这些页面部署到 CDN 或者其他存储服务中,以提升 Web 应用的性能和用户体验。
具体来说,SSG 的实现方式通常包括以下几个步骤:
- 在开发阶段,使用模板引擎等技术创建静态页面模板;
- 将需要展示的数据从后台 API 中获取或者通过其他渠道获取,并将其填充到静态页面模板中,生成完整的 HTML 页面;
- 使用构建工具(例如 Gatsby、Next.js 等)对静态页面进行构建,生成静态 HTML、CSS 和 JavaScript 文件;
- 部署生成好的静态文件到服务器或者 CDN 上,以供用户访问。
相比于传统的动态网页,SSG 具有如下优势:
- 加载速度快:由于不需要每次请求都动态地渲染页面,SSG 可以减少页面加载时间,从而提高用户体验和搜索引擎排名;
- 安全性高:由于没有后台代码和数据库,SSG 不容易受到 SQL 注入等攻击;
- 成本低:由于不需要动态服务器等设备,SSG 可以降低网站的运维成本和服务器负担。
需要注意的是,SSG 不适用于频繁更新的内容和动态交互等场景,但对于内容较为稳定和更新较少的网站则是一个性能优化的好选择。
1.22 说一下web worker?
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
通过postMessage将结果回传到主线程,这样复杂操作的时候,就不会阻塞主进程了
[阮一峰文章](Web Worker 使用教程 - 阮一峰的网络日志 (ruanyifeng.com))
1.23 说一下img的srcset作用?alt和title的区别?
- 响应式页面中经常用到根据屏幕密度设置不同的图片
- 这时就用到了 img 标签的srcset属性。srcset属性用于设置不同屏幕密度下,img 会自动加载不同的图片
- alt是图片失效的时候的备用图片地址,title是图片标题
1.24 说说你对 Dom 树的理解
什么是 DOM
从网络传给渲染引擎的 HTML 文件字节流是无法直接被渲染引擎理解的,所以要将其转化为渲染引擎能够理解的内部结构,这个结构就是 DOM。
DOM 提供了对 HTML 文档结构化的表述。
在渲染引擎中,DOM 有三个层面的作用:
- 从页面的视角来看,DOM 是生成页面的基础数据结构。
- 从 JavaScript 脚本视角来看,DOM 提供给 JavaScript 脚本操作的接口,通过这套接口,JavaScript 可以对 DOM 结构进行访问,从而改变文档的结构、样式和内容。
- 从安全视角来看,DOM 是一道安全防护线,一些不安全的内容在 DOM 解析阶段就被拒之门外了。
简言之,DOM 是表述 HTML 的内部数据结构,它会将 Web 页面和 JavaScript 脚本连接起来,并过滤一些不安全的内容。
DOM树如何生成
HTML 解析器(HTMLParser): 负责将 HTML 字节流转换为 DOM 结构。
那么网络进程是如何将数据传给HTML解析器的呢?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1w0cvHXF-1683893094351)(C:\Users\32063\AppData\Roaming\Typora\typora-user-images\image-20230511155523413.png)]
从图中我们可以知道,网络进程和渲染进程之间有一个共享数据通道,网络进程加载了多少数据, 就将数据传给HTML解析器进行解析。
HTML解析器接收到数据(字节流)之后,字节流将转化成DOM,过程如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2OHMEm6l-1683893094352)(C:\Users\32063\AppData\Roaming\Typora\typora-user-images\image-20230511155547442.png)]
有三个阶段:
1、通过分词器将字节流转化为Token。 分词器先将字节流转换为一个个 Token,分为 Tag Token 和文本 Token。
注意,这里的Token并不是我们之前理解的Token,这里就是一个片段。
2、Token解析为DOM节点。
3、将 DOM节点添加到DOM树中。
JavaScript影响DOM的生成
我们知道,JavaScript可以修改DOM,它也会影响DOM的生成。
1、内嵌 JavaScript 脚本 比如我们嵌入了一段
<script>
标签的代码,之前的解析过程都一样,但是解析到script标签时, 渲染引擎判断这是一段脚本,此时 HTML 解析器就会暂停 DOM 的解析, 因为接下来的 JavaScript 可能要修改当前已经生成的 DOM 结构。暂停解析之后,JavaScript 引擎介入,并执行
<script>
标签中的这段脚本。 脚本执行完成之后,HTML 解析器恢复解析过程,继续解析后续的内容,直至生成最终的 DOM。2、引入 JavaScript 文件 基本上跟之前是一致的,不同点在于,暂停解析之后执行JavaScript 代码,需要先下载这段 JavaScript 代码。
1.25 Node 和 Element 是什么关系?
Node与Element的关系,从继承方面思考可能清晰很多。
Element 继承于 Node,具有Node的方法,同时又拓展了很多自己的特有方法。
在Element的一些方法里,是明确区分了Node和Element的。比如说:childNodes与 children, parentNode与parentElement等方法。
Node的一些方法,返回值为Node,比如说文本节点,注释节点之类的,而Element的一些方法,返回值则一定是Element。
区分清楚这点了,也能避免很多低级问题。
简单的说就是Node是一个基类,DOM中的
Element
,Text和Comment
都继承于它。换句话说,Element
,Text
和Comment
是三种特殊的Node,它们分别叫做ELEMENT_NODE
,TEXT_NODE
和COMMENT_NODE
。所以我们平时使用的 html上的元素,即
Element
,是类型为ELEMENT_NODE
的Node
。
1.26 导致页面加载白屏时间长的原因有哪些,怎么进行优化?
一、白屏时间
白屏时间:即用户点击一个链接或打开浏览器输入URL地址后,从屏幕空白到显示第一个画面的时间。
二、白屏时间的重要性
当用户点开一个链接或者是直接在浏览器中输入URL开始进行访问时,就开始等待页面的展示。页面渲染的时间越短,用户等待的时间就越短,用户感知到页面的速度就越快。这样可以极大的提升用户的体验,减少用户的跳出,提升页面的留存率。
三、白屏的过程
从输入url,到页面的画面展示的过程
1、首先,在浏览器地址栏中输入url
2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
3、在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
5、握手成功后,浏览器向服务器发送http请求,请求数据包。
6、服务器处理收到的请求,将数据返回至浏览器
7、浏览器收到HTTP响应
8、读取页面内容,浏览器渲染,解析html源码
9、生成Dom树、解析css样式、js交互,渲染显示页面
浏览器下载HTML后,首先解析头部代码,进行样式表下载,然后继续向下解析HTML代码,构建DOM树,同时进行样式下载。当DOM树构建完成后,立即开始构造CSSOM树。理想情况下,样式表下载速度够快,DOM树和CSSOM树进入一个并行的过程,当两棵树构建完毕,构建渲染树,然后进行绘制。
Tips:浏览器安全解析策略对解析HTML造成的影响:
当解析HTML时遇到内联JS代码,会阻塞DOM树的构建,会先执行完JS代码;当CSS样式文件没有下载完成时,浏览器解析HTML遇到了内联JS代码,此时,浏览器暂停JS脚本执行,暂停HTML解析。直到CSS文件下载完成,完成CSSOM树构建,重新恢复原来的解析。
JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞 JavaScript 的执行,所以在实际的工程中需要重点关注 JavaScript 文件和样式表文件,使用不当会影响到页面性能的。
四、白屏-性能优化
1. DNS解析优化
针对DNS Lookup环节,我们可以针对性的进行DNS解析优化。
- DNS缓存优化
- DNS预加载策略
- 稳定可靠的DNS服务器
2. TCP网络链路优化
多花点钱吧
3. 服务端处理优化
服务端的处理优化,是一个非常庞大的话题,会涉及到如Redis缓存、数据库存储优化或是系统内的各种中间件以及Gzip压缩等…
4. 浏览器下载、解析、渲染页面优化
根据浏览器对页面的下载、解析、渲染过程,可以考虑一下的优化处理:
- 尽可能的精简HTML的代码和结构
- 尽可能的优化CSS文件和结构
- 一定要合理的放置JS代码,尽量不要使用内联的JS代码
- 将渲染首屏内容所需的关键CSS内联到HTML中,能使CSS更快速地下载。在HTML下载完成之后就能渲染了,页面渲染的时间提前,从而缩短首屏渲染时间;
- 延迟首屏不需要的图片加载,而优先加载首屏所需图片(offsetTop<clientHeight)
document.documentElement.clientHeight//获取屏幕可视区域的高度
element.offsetTop//获取元素相对于文档顶部的高度
因为JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞 JavaScript 的执行,所以在实际的工程中需要重点关注 JavaScript 文件和样式表文件,使用不当会影响到页面性能的。
1.27 渐进式jpg有了解过吗?
渐进式 JPEG(Progressive JPEG),即PJPEG,是该标准的三种流行压缩模式之一。
渐进式 JPEG 以特定方式压缩照片和图形,与基线 JPEG 不同,PJPEG 在 Web 浏览器中呈现时,会首先给出模糊图像的外观。然后一点一点地开始图片渲染,直到它显示完全渲染的图像。浏览器实际上是逐行解释图像,但在占位符中提供了完整图像的模糊预览。随着 Web 浏览器的渲染引擎处理数据,图像的对比度开始变得更清晰、更详细。直到最后渲染完毕,用户将看到完整的清晰图像。
PJPEG 能够起到一种很有意义的心理效果,让用户有东西可看,而不必坐着干等大型图像慢慢显示在屏幕上。
PJPEG 适用于大部分常用的浏览器,包括
Chrome
、Firefox
和Internet Explorer 9
及更高版本。旧版本的 Internet Explorer 在显示渐进式 JPEG 时存在一些问题,不过这只是很小一部分用户。而不支持渐进式 JPEG 格式的浏览器会像普通 JPEG 一样加载照片。
1.28 怎么实现“点击回到顶部”的功能?
1、锚点
使用锚点链接是一种简单的返回顶部的功能实现。
该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置。
<body style="height:2000px;">
<div id="topAnchor"></div>
<a href="#topAnchor" style="position:fixed;right:0;bottom:0">回到顶部</a>
</body>
2、scrollTop
scrollTop属性表示被隐藏在内容区域上方的像素数。
元素未滚动时,scrollTop的值为0,如果元素被垂直滚动了,scrollTop的值大于0,且表示元素上方不可见内容的像素宽度
由于scrollTop是可写的,可以利用scrollTop来实现回到顶部的功能
<body style="height:2000px;">
<button id="test" style="position:fixed;right:0;bottom:0">回到顶部</button>
<script>
test.onclick = function(){
document.body.scrollTop = document.documentElement.scrollTop = 0;
}
</script>
</body>
3、scrollTo
scrollTo(x,y)方法滚动当前window中显示的文档,让文档中由坐标x和y指定的点位于显示区域的左上角
设置scrollTo(0,0)可以实现回到顶部的效果
<body style="height:2000px;">
<button id="test" style="position:fixed;right:0;bottom:0">回到顶部</button>
<script>
test.onclick = function(){
scrollTo(0,0);
}
</script>
</body>
4、scrollBy()
scrollBy(x,y)方法滚动当前window中显示的文档,x和y指定滚动的相对量
只要把当前页面的滚动长度作为参数,逆向滚动,则可以实现回到顶部的效果
<body style="height:2000px;">
<button id="test" style="position:fixed;right:0;bottom:0">回到顶部</button>
<script>
test.onclick = function(){
var top = document.body.scrollTop || document.documentElement.scrollTop
scrollBy(0,-top);
}
</script>
</body>
5、scrollIntoView()
Element.scrollIntoView方法滚动当前元素,进入浏览器的可见区域
该方法可以接受一个布尔值作为参数。如果为true,表示元素的顶部与当前区域的可见部分的顶部对齐(前提是当前区域可滚动);如果为false,表示元素的底部与当前区域的可见部分的尾部对齐(前提是当前区域可滚动)。如果没有提供该参数,默认为true
使用该方法的原理与使用锚点的原理类似,在页面最上方设置目标元素,当页面滚动时,目标元素被滚动到页面区域以外,点击回到顶部按钮,使目标元素重新回到原来位置,则达到预期效果
<body style="height:2000px;">
<div id="target"></div>
<button id="test" style="position:fixed;right:0;bottom:0">回到顶部</button>
<script>
test.onclick = function(){
target.scrollIntoView();
}
</script>
</body>
1.29 如何实现SEO优化
SEO主要分为内部和外部两个方向。
一、内部优化
- META 标签优化:例如:TITLE,KEYWORDS,DESCRIPTION (TDK)等的优化
- 内部链接的优化,包括相关性链接(Tag 标签),锚文本链接,各导航链接,及图片链接
- 网站内容更新:每天保持站内的更新(主要是文章的更新等)
- 服务器端渲染(SSR)
二、外部优化
- 外部链接类别:博客、论坛、B2B、新闻、分类信息、贴吧、知道、百科、相关信息网等尽量保持链接的多样性
- 外链运营:每天添加一定数量的外部链接,使关键词排名稳定提升。
- 外链选择:与一些和你网站相关性比较高,整体质量比较好的网站交换友情链接,巩固稳定关键词排名
1.30 SEO是什么?
SEO(Search Engine Optimization),汉译为搜索引擎优化。
搜索引擎优化是一种利用搜索引擎的搜索规则来提高目前网站在有关搜索引擎内的自然排名的方式。
SEO是指为了从搜索引擎中获得更多的免费流量,从网站结构、内容建设方案、用户互动传播、页面等角度进行合理规划,使网站更适合搜索引擎的索引原则的行为。
1.31 DNS 预解析是什么?怎么实现?
DNS优化
在介绍dns-prefetch
之前,先要提下当前对于DNS优化主流方法。
一般来说,一次DNS解析需要耗费 20-120ms,所以为了优化DNS,我们可以考虑两个方向:
- 减少DNS请求次数
- 缩短DNS解析时间
dns-prefetch
什么是dns-prefetch?
dns-prefetch
(DNS预获取)是前端网络性能优化的一种措施。它根据浏览器定义的规则,提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,进而提高网站的访问速度。
为什么要用dns-prefetch?
每当浏览器从(第三方)服务器发送一次请求时,都要先通过DNS解析将该跨域域名解析为 IP地址,然后浏览器才能发出请求。
如果某一时间内,有多个请求都发送给同一个服务器,那么DNS解析会多次并且重复触发。这样会导致整体的网页加载有延迟的情况。
我们知道,虽然DNS解析占用不了多大带宽,但是它会产生很高的延迟,尤其是对于移动网络会更为明显。
因此,为了减少DNS解析产生的延迟,我们可以通过dns-prefetch
预解析技术有效地缩短DNS解析时间。
<link rel="dns-prefetch" href="https://baidu.com/">
dns-prefetch背后原理
当浏览器访问一个域名的时候,需要解析一次DNS,获得对应域名的ip地址。 在解析过程中,按照:
- 浏览器缓存
- 系统缓存
- 路由器缓存
- ISP(运营商)DNS缓存
- 根域名服务器
- 顶级域名服务器
- 主域名服务器
的顺序逐步读取缓存,直到拿到IP地址。
dns-prefetch
就是在将解析后的IP缓存在系统中。
这样,dns-prefetch
就有效地缩短了DNS解析时间。因为,在本地操作系统做了DNS缓存,使得DNS在解析的过程中,提前在系统缓存中找到了对应IP。
这样一来, 后续的解析步骤就不用执行了,进而也就缩短了DNS解析时间。
假如浏览器首次将一个域名解析为IP地址,并缓存至操作系统,那么下一次DNS解析时间可以低至0-1ms。
倘若结果不缓存在系统,那么就需要读取路由器的缓存,进而后续的解析时间最小也要约15ms。
如果路由器缓存也不存在,则需要读取ISP(运营商)DNS缓存,一般像taobao.com
、baidu.com
这些常见的域名,读取ISP(运营商)DNS缓存需要的时间在80-120ms,如果是不常见的域名,平均需要200-300ms。
一般来说,大部分的网站到运营商这块都能找到IP。
那也就是说,dns-prefetch
可以给DNS解析过程带来15-300ms的提升,尤其是一些大量引用很多其他域名资源的网站,提升效果就更加明显了
浏览器DNS缓存与dns-prefetch
现代浏览器为了优化DNS解析,也设有了浏览器DNS缓存。
每当在首次DNS解析后会对其IP进行缓存。至于缓存时长,每种浏览器都不一样,比如Chrome的过期时间是1分钟,在这个期限内不会重新请求DNS。
Tip:
每当Chrome浏览器启动的时候,就会自动的快速解析浏览器最近一次启动时记录的前10个域名。所以经常访问的网址就不存在DNS解析的延迟,进而打开速度更快。
而dns-prefetch
相当于在浏览器缓存之后,在本地操作系统中做了DNS缓存,个人理解,为的是给浏览器缓存做保障,尽量让DNS解析出本地,以此来做了又一层DNS解析优化。
一般来说,DNS在系统的缓存时间是大于浏览器的。
浏览器与系统DNS缓存时间
TTL(Time-To-Live),就是一条域名解析记录在DNS服务器中的存留时间
- 浏览器DNS缓存的时间跟DNS服务器返回的TTL值无关, 它的缓存时间取决于浏览器自身设置。
- 系统缓存会参考DNS服务器响应的TTL值,但是不完全等于TTL值。
国内和国际上很多平台的TTL值都是以秒为单位的,很多的默认值都是3600,也就是默认缓存1小时。
dns-prefetch
缺点
dns-prefetch
最大的缺点就是使用它太多。
过多的预获取会导致过量的DNS解析,对网络是一种负担。
最佳实践
请记住以下三点:
dns-prefetch
仅对跨域域上的 DNS查找有效,因此请避免使用它来指向相同域。这是因为,到浏览器看到提示时,您站点域背后的IP已经被解析。- 除了link 还可以通过使用 HTTP链接字段将
dns-prefetch
(以及其他资源提示)指定为 HTTP标头:
Link: <https://fonts.gstatic.com/>; rel=dns-prefetch
- 考虑将
dns-prefetch
与preconnect(
预连接)
提示配对。
由于dns-prefetch
仅执行 DNS查找,不像preconnect
会建立与服务器的连接。
如果站点是通过HTTPS服务的,两者的组合会涵盖DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供进一步减少跨域请求的感知延迟的机会。如下所示:
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.gstatic.com/">
Note: 如果页面需要建立与许多第三方域的连接,则将它们预先连接会适得其反。 preconnect
提示最好仅用于最关键的连接。对于其他的,只需使用 <link rel="dns-prefetch">
即可节省第一步的时间DNS查找。
1.32 indexDB怎么使用
IndexedDB 是一种浏览器本地数据库技术,与传统的关系型数据库或非关系型数据库不同,它主要目的是为 web 应用提供一个在客户端存储数据的机制,从而允许用户离线操作或缓存大量数据的情况下,得到更好的性能和可靠性。
IndexedDB 使用了 key-value 的方式来进行数据存储。每个 IndexedDB 数据库由多个对象仓库(Object Store)组成,每个对象仓库包含了对应的数据记录集合。以下是基本的使用步骤:
- 打开数据库 可以通过 IndexedDB 对象及其 open 方法打开一个指定名称的数据库,并指明需要创建或升级数据库时相应声明该数据库的配置信息,如版本号、对象仓库和索引等。
javascript复制代码// 前提条件:浏览器支持 IndexedDB
let request = indexedDB.open("myDatabase", 2);
request.onerror = function(event) {
console.log("打开数据库失败");
};
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("customers", { keyPath: "id" });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("email", "email", { unique: true });
};
request.onsuccess = function(event) {
let db = event.target.result;
}
- 创建对象仓库 在打开 IndexedDB 数据库后,可以通过调用
createObjectStore()
方法来创建对象仓库。您可以指定主键和索引,以便在查询数据库时更有效地操作数据。
javascript复制代码let objectStore = db.createObjectStore("customers", { keyPath: "id" });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("email", "email", { unique: true });
- 添加数据记录 使用事务(transaction)来添加或更新数据记录。在事务内调用应用的
add()
函数提交要存储的数据,并指定其属于哪个对象仓库。需要注意,IndexedDB 中所有操作都是异步的,并且受到浏览器安全机制的限制。
javascript复制代码let customerData = [
{ id: 1, name: "John Doe", email: "john@doe.com" },
{ id: 2, name: "Jane Doe", email: "jane@doe.com" }
];
let transaction = db.transaction(["customers"], "readwrite");
let objectStore = transaction.objectStore("customers");
customerData.forEach(function(customer) {
let request = objectStore.add(customer);
request.onsuccess = function(event) {
console.log("新增数据成功");
};
});
- 读取数据记录 读取数据文件与添加数据文件类似,同样通过开启事务和打开对应对象仓库,然后使用
openCursor()
或get()
等方法遍历并获取其中的数据记录。
javascript复制代码let transaction = db.transaction(["customers"]);
let objectStore = transaction.objectStore("customers");
let request = objectStore.get(1);
request.onerror = function(event) {
console.log("读取数据失败");
};
request.onsuccess = function(event) {
if (request.result) {
console.log("读取到的数据为:" + JSON.stringify(request.result));
} else {
console.log
[Network Error]
1.33 HTML5 有哪些 drag 相关的 API ?
- dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发。
- darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
- dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。
- dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。
- dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。
- drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。
- dragend:事件主体是被拖放元素,在整个拖放操作结束时触发。
1.34 浏览器乱码的原因是什么?如何解决?
产生乱码的原因:
- 网页源代码是
gbk
的编码,而内容中的中文字是utf-8
编码的,这样浏览器打开即会出现html
乱码,反之也会出现乱码;html
网页编码是gbk
,而程序从数据库中调出呈现是utf-8
编码的内容也会造成编码乱码;- 浏览器不能自动检测网页编码,造成网页乱码。
解决办法:
- 使用软件编辑HTML网页内容;
- 如果网页设置编码是
gbk
,而数据库储存数据编码格式是UTF-8
,此时需要程序查询数据库数据显示数据前进程序转码;- 如果浏览器浏览时候出现网页乱码,在浏览器中找到转换编码的菜单进行转换。
1.35 js和css是如何影响DOM树构建的?
CSS不会阻塞DOM的解析,但是会影响JAVAScript的运行,javaSscript会阻止DOM树的解析,最终css(CSSOM)会影响DOM树的渲染,也可以说最终会影响渲染树的生成。
接下来我们先看javascript对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>
两段div中间插入一段JavaScript脚本,这段脚本的解析过程就有点不一样了。
当解析到script脚本标签时,HTML解析器暂停工作,javascript引擎介入,并执行script标签中的这段脚本。
因为这段javascript脚本修改了DOM中第一个div中的内容,所以执行这段脚本之后,div节点内容已经修改为time.geekbang了。脚本执行完成之后,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脚本修改成了通过javaScript文件加载。
其整个执行流程还是一样的,执行到JAVAScript标签时,暂停整个DOM的解析,执行javascript代码,不过这里执行javascript时,需要现在在这段代码。这里需要重点关注下载环境,因为javascript文件的下载过程会阻塞DOM解析,而通常下载又是非常耗时的,会受到网络环境、javascript文件大小等因素的影响。
优化机制:
谷歌浏览器做了很多优化,其中一个主要的优化就是预解析操作。当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析HTML文件中包含的JavaScript、CSS等相关文件,解析到相关文件之后,会开启一个预解析线程,用来分析HTML文件中包含的javascprit、css等相关文件、解析到相关文件之后,预解析线程会提前下载这些文件。
再回到 DOM 解析上,我们知道引入 JavaScript 线程会阻塞 DOM,不过也有一些相关的策略来规避,比如使用 CDN 来加速 JavaScript 文件的加载,压缩 JavaScript 文件的体积。
另外,如果 JavaScript 文件中没有操作 DOM 相关代码,就可以将该 JavaScript 脚本设置为异步加载,通过 async 或 defer 来标记代码,使用方式如下所示:
<script async type="text/javascript" src='foo.js'></script>
<script defer type="text/javascript" src='foo.js'></script>
async和defer区别:
- async:脚本并行加载,加载完成之后立即执行,执行时机不确定,仍有可能阻塞HTML解析,执行时机在load事件派发之前。
- defer:脚本并行加载,等待HTML解析完成之后,按照加载顺序执行脚本,执行时机DOMContentLoaded事件派发之前。
html页面中有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>
该示例中,JavaScript 代码出现了 div1.style.color = ‘red’
的语句,它是用来操纵 CSSOM 的,所以在执行 JavaScript 之前,需要先解析 JavaScript 语句之上所有的CSS 样式。所以如果代码里引用了外部的 CSS 文件,那么在执行 JavaScript 之前,还需要等待外部的 CSS 文件下载完成,并解析生成 CSSOM 对象之后,才能执行 JavaScript 脚本。
而 JavaScript 引擎在解析 JavaScript 之前,是不知道 JavaScript 是否操纵了 CSSOM的,所以渲染引擎在遇到 JavaScript 脚本时,不管该脚本是否操纵了 CSSOM,都会执行CSS 文件下载,解析操作,再执行 JavaScript 脚本。所以说 JavaScript 脚本是依赖样式表的,这又多了一个阻塞过程。
总结:通过上面三点的分析,我们知道了 JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞js的执行。
1.36 表单中readonly和disabled的区别
- 共同点:能够使用户不能改变表单中的内容
- 不同点:
1、readonly只对input和textarea有效,但是disabled对所有的表单元素都是有效的,包括radio、checkbox
2、readonly可以获取到焦点,只是不能修改。disabled设置的文本框无法获取焦点
3、如果表单的字段是disabled,则该字段不会发送(表单传值)和序列化
1.37 主流浏览器及内核
Google chrome:webkit/blink
safari:webkit
IE:trident
firefox:gecko
Opera:presto/webkit/blink
1.38 说说你对以下几个页面生命周期事件的理解:DOMContentLoaded,load,beforeunload,unload
HTML 页面的生命周期包含三个重要事件:
- DOMContentLoaded —— 浏览器已完全加载 HTML,并构建了 DOM 树,但像 和样式表之类的外部资源可能尚未加载完成。
- load —— 浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。
- beforeunload/unload —— 当用户正在离开页面时。
每个事件都是有用的:
- DOMContentLoaded 事件 —— DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口。
- load 事件 —— 外部资源已加载完成,样式已被应用,图片大小也已知了。
- beforeunload 事件 —— 用户正在离开:我们可以检查用户是否保存了更改,并询问他是否真的要离开。
- unload 事件 —— 用户几乎已经离开了,但是我们仍然可以启动一些操作,例如发送统计数据。
DOMContentLoaded 和脚本
当浏览器处理一个 HTML 文档,并在文档中遇到
因此,DOMContentLoaded 肯定在下面的这些脚本执行结束之后发生。
此规则有两个例外:
- 具有 async 特性(attribute)的脚本不会阻塞 DOMContentLoaded,稍后 我们会讲到。
- 使用 document.createElement(‘script’) 动态生成并添加到网页的脚本也不会阻塞 DOMContentLoaded。
DOMContentLoaded 和样式
外部样式表不会影响 DOM,因此 DOMContentLoaded 不会等待它们。
但这里有一个陷阱。如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成。原因是,脚本可能想要获取元素的坐标和其他与样式相关的属性。因此,它必须等待样式加载完成。
当 DOMContentLoaded 等待脚本时,它现在也在等待脚本前面的样式。
浏览器内建的自动填充
Firefox,Chrome 和 Opera 都会在 DOMContentLoaded 中自动填充表单。
例如,如果页面有一个带有登录名和密码的表单,并且浏览器记住了这些值,那么在 DOMContentLoaded 上,浏览器会尝试自动填充它们(如果得到了用户允许)。
因此,如果 DOMContentLoaded 被需要加载很长时间的脚本延迟触发,那么自动填充也会等待。你可能在某些网站上看到过(如果你使用浏览器自动填充)—— 登录名/密码字段不会立即自动填充,而是在页面被完全加载前会延迟填充。这实际上是 DOMContentLoaded 事件之前的延迟。
window.onload
当整个页面,包括样式、图片和其他资源被加载完成时,会触发 window 对象上的 load 事件。可以通过 onload 属性获取此事件。
window.onunload
当访问者离开页面时,window 对象上的 unload 事件就会被触发。我们可以在那里做一些不涉及延迟的操作,例如关闭相关的弹出窗口。
有一个值得注意的特殊情况是发送分析数据。
假设我们收集有关页面使用情况的数据:鼠标点击,滚动,被查看的页面区域等。
自然地,当用户要离开的时候,我们希望通过 unload 事件将数据保存到我们的服务器上。
有一个特殊的 navigator.sendBeacon(url, data) 方法可以满足这种需求,详见规范 https://w3c.github.io/beacon/。
它在后台发送数据,转换到另外一个页面不会有延迟:浏览器离开页面,但仍然在执行 sendBeacon。
当 sendBeacon 请求完成时,浏览器可能已经离开了文档,所以就无法获取服务器响应(对于分析数据来说通常为空)。
还有一个 keep-alive 标志,该标志用于在 fetch 方法中为通用的网络请求执行此类“离开页面后”的请求。你可以在 Fetch API 一章中找到更多相关信息。
如果我们要取消跳转到另一页面的操作,在这里做不到。但是我们可以使用另一个事件 —— onbeforeunload。
window.onbeforeunload
如果访问者触发了离开页面的导航(navigation)或试图关闭窗口,beforeunload 处理程序将要求进行更多确认。
如果我们要取消事件,浏览器会询问用户是否确定。
总结
页面生命周期事件:
- 当 DOM 准备就绪时,document 上的 DOMContentLoaded 事件就会被触发。在这个阶段,我们可以将 JavaScript 应用于元素。
- 诸如
<script>...</script>
或<script src="..."></script>
之类的脚本会阻塞 DOMContentLoaded,浏览器将等待它们执行结束。 - 图片和其他资源仍然可以继续被加载。
- 诸如
- 当页面和所有资源都加载完成时,window 上的 load 事件就会被触发。我们很少使用它,因为通常无需等待那么长时间。
- 当用户想要离开页面时,window 上的 beforeunload 事件就会被触发。如果我们取消这个事件,浏览器就会询问我们是否真的要离开(例如,我们有未保存的更改)。
- 当用户最终离开时,window 上的 unload 事件就会被触发。在处理程序中,我们只能执行不涉及延迟或询问用户的简单操作。正是由于这个限制,它很少被使用。我们可以使用 navigator.sendBeacon 来发送网络请求。
1.39 使用input标签上传图片时,怎样触发默认拍照功能?
capture 属性用于指定文件上传控件中媒体拍摄的方式。
可选值:
- user 前置
- environment 后置
- camera 相机
- camcorder 摄像机
- microphone 录音
<input type='file' accept='image/*;' capture='camera'>
给input上传多张照片
<input type="file" name="files" multiple/>
1.40 如何禁止input展示输入的历史记录?
在输入input时会提示原来输入过的内容,还会出现下拉的历史记录,禁止这种情况只需在input中加入: autocomplete=“off”
<input type="text" autocomplete="off" />
autocomplete 属性是用来规定输入字段是否启用自动完成的功能。
1.41 iconfont是什么?有什么优缺点?
什么是 IconFont
顾名思义,IconFont 就是字体图标。严格地说,就是一种字体,但是,它们不包含字母或数字,而是包含符号和字形。您可以使用 CSS 设置样式,就像设置常规文本一样,这使得 IconFont 成为 Web 开发时图标的热门选择。
优点
- 可以方便地将任何 CSS 效果应用于它们。
- 因为它们是矢量图形,所以它们是可伸缩的。这意味着我们可以在不降低质量的情况下伸缩它们。
- 我们只需要发送一个或少量 HTTP 请求来加载它们,而不是像图片,可能需要多个 HTTP 请求。
- 由于尺寸小,它们加载速度快。
- 它们在所有浏览器中都得到支持(甚至支持到 IE6)。
不足
- 不能用来显示复杂图像
- 通常只限于一种颜色,除非应用一些 CSS 技巧
- 字体图标通常是根据特定的网格设计的,例如 16x16, 32×32, 48×48等。如果由于某种原因将网格系统改为25×25,可能不会得到清晰的结果
1.42 页面统计数据中,常用的 PV、UV 指标分别是什么?
PV(页面访问量)
即页面浏览量或点击量,用户每1次对网站中的每个网页访问均被记录1个PV。
用户对同一页面的多次访问,访问量累计,用以衡量网站用户访问的网页数量。
UV(独立访客)
是指通过互联网访问、浏览这个网页的自然人。访问您网站的一台电脑客户端为一个访客。
00:00-24:00内相同的客户端只被计算一次。
1.43 一台设备的dpr,是否是可变的?
devicePixelRatio
,中文名称是设备像素比。这个概念在移动开发的时候会被特别关注,因为它关系到了整个画面的观感、布局甚至是清晰度。在JavaScript BOM中,它是window全局对象下的一个属性,它的定义如下:
dpr = 设备像素 / CSS像素
也有文章把设备像素称为物理像素,把CSS像素称为独立像素(DIPs),但所指的都是同样概念:
(1) 首先说设备像素。举手机的例子来说,设备像素也就是在手机广告上经常会看到的19201080像素或1280720像素,也就是常说的分辨率为1080p或720p。它所指的是设备上有多少个能够显示一种特定颜色的最小区域,在任何设备中这个数值都是不会变的。
(2) 再说CSS像素,它的一种更广义的叫法是独立像素。CSS像素是为web开发者所打造的,是在CSS和JavaScript中使用的一个抽象的层,我们在CSS中定义的width: 100px;、font-size: 16px;等属性都是指CSS像素。而相对于CSS像素,设备像素这个概念在前端中几乎用不上(除了screen.width/height)。
那么,从定义来看,dpr的意义就是:在一个设备(的每个方向)上,每个CSS像素会被多少个实际的物理像素来显示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1K453lNx-1683893094352)(C:\Users\32063\AppData\Roaming\Typora\typora-user-images\image-20230512093200340.png)]
上图中,一个蓝色方块代表一个设备像素,一个黄色方块代表一个CSS像素。我们可以通过这张图来理清dpr的概念:
- 如图左,一个设备像素覆盖了多个CSS像素,dpr < 1,对应用户的缩小操作;
- 如图右,一个CSS像素覆盖了多个设备像素,dpr > 1,对应用户的放大操作。
由于用户的缩放操作会改变dpr,所以设备dpr是在默认缩放为100%的情况下定义的。
1.44 html和css中的图片加载与渲染规则是什么样的?
Web浏览器先会把获取到的HTML代码解析成一个DOM树,HTML中的每个标签都是DOM树中的一个节点,包括display: none隐藏的标签,还有JavaScript动态添加的元素等。浏览器会获取到所有样式,并会把所有样式解析成样式规则,在解析的过程中会去掉浏览器不能识别的样式。
浏览器将会把DOM树和样式规则组合在一起(DOM元素和样式规则匹配)后将会合建一个渲染树(Render Tree),渲染树类似于DOM树,但两者别还是很大的:渲染树能识别样式,渲染树中每个节点(NODE)都有自己的样式,而且渲染树不包含隐藏的节点(比如display:none的节点,还有内的一些节点),因为这些节点不会用于渲染,也不会影响节点的渲染,因此不会包含到渲染树中。一旦渲染树构建完毕后,浏览器就可以根据渲染树来绘制页面了。
简单的归纳就是浏览器渲染Web页面大约会经过六个过程:
- 解析HTML,构成DOM树
- 解析加载的样式,构建样式规则树
- 加载JavaScript,执行JavaScript代码
- DOM树和样式规则树进行匹配,构成渲染树
- 计算元素位置进行页面布局
- 绘制页面,最终在浏览器中呈现
是不是会感觉这个和我们图像加载渲染没啥关系一样,事实并非如此,因为img、picture或者background-image都是DOM树或样式规则中的一部分,那么咱们套用进来,图片加载和渲染的时机有可能是下面这样:
- 解析HTML时,如果遇到img或picture标签,将会加载图片
- 解析加载的样式,遇到background-image时,并不会加载图片,而会构建样式规则树
- 加载JavaScript,执行JavaScript代码,如果代码中有创建img元素之类,会添加到DOM树中;如查有添加background-image规则,将会添加到样式规则树中
- DOM树和样式规则匹配时构建渲染树,如果DOM树节点匹配到样式规则中的backgorund-image,则会加载背景图片
- 计算元素(图片)位置进行布局
- 开始渲染图片,浏览器将呈现渲染出来的图片
上面套用浏览器渲染页面的机制,但图片加载与渲染还是有一定的规则。因为,页面中不是所有的(或picture)元素引入的图片和background-image引入的背景图片都会加载的。那么就引发出新问题了,什么时候会真正的加载,加载规则又是什么?
先概括一点:
Web页面中不是所有的图片都会加载和渲染!
根据前面介绍的浏览器加载和渲染机制,我们可以归纳为:
- 、和设置background-image的元素遇到display:none时,图片会加载但不会渲染
- 、和设置background-image的元素祖先元素设置display:none时,background-image不会渲染也不会加载,而img和picture引入的图片不会渲染但会加载
- 、和background-image引入相同路径相同图片文件名时,图片只会加载一次
- 样式文件中background-image引入的图片,如果匹配不到DOM元素,图片不会加载
- 伪类引入的background-image,比如:hover,只有当伪类被触发时,图片才会加载.
1.45 mete标签中的viewport 有什么用?
什么是 Viewport?
viewport 是用户网页的可视区域。
viewport 翻译为中文可以叫做**“视区”**。
手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。
设置 Viewport
一个常用的针对移动网页优化过的页面的 viewport meta 标签大致如下:
1<meta name="viewport" content="width=device-width, initial-scale=1.0">
- width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
- height:和 width 相对应,指定高度。
- initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
- maximum-scale:允许用户缩放到的最大比例。
- minimum-scale:允许用户缩放到的最小比例。
- user-scalable:用户是否可以手动缩放。
1.46 前端该如何选择图片的格式
图片的类型目前就分为两种:
- 位图
- 矢量图
位图
所谓位图就是用像素点拼起来的图也叫点阵图,平时我们用到的png、jpg等图片就是位图。
矢量图
矢量图,也叫做向量图。矢量图并不纪录画面上每一点的信息,而是纪录了元素形状及颜色的算法,当你打开一幅矢量图的时候,软件对图形对应的函数进行运算,将运算结果图形的形状和颜色显示给你看。
无论显示画面是大还是小,画面上的对象对应的算法是不变的,所以,即使对画面进行倍数相当大的缩放,它也不会像位图那样会失真。
常见的就是svg格式的。
图片的压缩类型
- 无压缩
- 有损压缩
- 无损压缩
无压缩
无压缩的图片格式不对图片数据进行压缩处理,能准确地呈现原图片。例如BMP格式的图片。
有损压缩
指在压缩文件大小的过程中,损失了一部分图片的信息,也即降低了图片的质量(即图片被压糊了),并且这种损失是不可逆的。
常见的有损压缩手段是按照一定的算法将临近的像素点进行合并。压缩算法不会对图片所有的数据进行编码压缩,而是在压缩的时候,去除了人眼无法识别的图片细节。因此有损压缩可以在同等图片质量的情况下大幅降低图片的体积。例如jpg格式的图片使用的就是有损压缩。
无损压缩
在压缩图片的过程中,图片的质量没有任何损耗。我们任何时候都可以从无损压缩过的图片中恢复出原来的信息。
压缩算法对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的体积。例如png、gif使用的就是无损压缩。
图片位数
图片位数通常分为8、16、24、32
- 图片位数越大,能表示的颜色越多,同时占用的体积也约大。例如8位图片支持256种颜色,即2的8次方。
- 图片位数越大,颜色过渡也就越细腻,携带的色彩信息可以更加丰富。
- 32位跟24位的区别就是多了一个Alpha通道,用来支持半透明,其他的跟24位基本一样。
常见的图片的格式
GIF
GIF的全称是Graphics Interchange Format
,可译为图形交换格式,是在1987年由Compu Serve公司为了填补跨平台图像格式的空白而发展起来的。
GIF采用的是Lempel-Zev-Welch(LZW)压缩算法,最高支持256种颜色。由于这种特性,GIF比较适用于色彩较少的图片,比如卡通造型、公司标志等等。如果碰到需要用24位真彩色的场合,那么GIF的表现力就有限了。
GIF格式图片最大的特性是帧动画,相比古老的bmp格式,尺寸较小,而且支持透明(不支持半透明,因为不支持 Alpha 透明通道 )和动画。
优点:
- 体积小
- 支持动画
缺点:
- 由于采用了8位压缩,最多只能处理256种颜色
JPEG/JPG
JPEG是Joint Photographic Experts Group
(联合图像专家组)的缩写,文件后辍名为".jpg"或".jpeg",是常用的图像文件格式,由一个软件开发联合会组织制定,是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要的资料会被丢失,因此容易造成图像数据的损伤。尤其是使用过高的压缩比例,将使最终解压缩后恢复的图像质量明显降低,如果追求高品质图像,不宜采用过高压缩比例。
优点:
- 采用有损压缩,压缩后体积更小
- 支持24位真彩色
- 支持渐进式加载
缺点:
- 有损压缩会损坏图片的质量
- 不支持透明/半透明
渐进式jpeg(progressive jpeg)
渐进式jpg文件包含多次扫描,这些扫描顺寻的存储在jpg文件中。打开文件过程中,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。
PNG
png,即便携式网络图形是一种无损压缩的位图片形格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。
png支持8位、24位、32位3种,我们通常叫它们png8、png24、png32。
优点:
- 无损压缩
- 支持透明、半透明
- 最高支持24位真彩色图像以及8位灰度图像,从而彻底地消除锯齿边缘。
缺点:
- 与jpg的有损耗压缩相比,png提供的压缩量较少
- 不支持动画,如需支持动画还得使用apng
APNG
APNG(Animated Portable Network Graphics)是一个基于PNG(Portable Network Graphics)的位图动画格式。实际上就是多张png组成的动图。MAC电脑打开可以看到组成apng的每一张图。
优点:
- 支持png的所有优点
- 支持动画
缺点:
- 浏览器支持情况较差
WEBP
WebP是由Google最初在2010年发布,目标是减少文件大小。它能同时支持无损压缩和有损压缩。
它几乎集成了以上所有图片的优点,并且能够拥有更高的压缩率,但是浏览器支持率还不够理想。
SVG
SVG是一种用XML定义的语言,用来描述二维矢量及矢量/栅格图形。SVG提供了3种类型的图形对象:矢量图形(例如:由直线和曲线组成的路径)、图象、文本。图形对象还可进行分组、添加样式、变换、组合等操作,特征集包括嵌套变换、剪切路径、alpha蒙板、滤镜效果、模板对象和其它扩展。
SVG图形是可交互的和动态的,可以在SVG文件中嵌入动画元素或通过脚本来定义动画。
SVG与上面图片不同的是它是矢量图,无论你怎么放大,它都不会失真;同时,SVG文件通常要比比JPEG和PNG格式的文件要小很多。
优点:
- SVG 可被非常多的工具读取和修改(比如记事本)
- SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
- SVG 是可伸缩
- SVG 图像可在任何的分辨率下被高质量地打印
- SVG 可在图像质量不下降的情况下被放大
- SVG 可以与 JavaScript 技术一起运行
- SVG 文件是纯粹的 XML
缺点:
- 渲染成本相对于其他格式图片比较高,对于性能有影响。
- 需要学习成本,因为SVG是一种用XML定义的语言。