前端面试题汇总
https://www.one-tab.com/page/DUzvPkoFTy67kYevpvS2WQ?utm_source=wechat_session&utm_medium=social&utm_oi=775824004362543104 (面试汇总)
HTTP/HTML/浏览器
http和https
基本概念:
-
http
超文本传输协议,是一个客户端和服务端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议。 -
https
是以安全为目标的HTTP通道,简单来说,是HTTP的安全版,即HTTP下加入SSL层。
区别:
- http传输数据没有加密,是明文传输。
- https需要ca证书,费用高。
tcp三次握手
1. 第一次握手,服务器确认自己可以收到客户端的信息。
2. 客户端确定服务器收到了发送的信息,并确定自己可以收到服务器的信息。
3. 服务器确定客户端收到了自己的信息
TCP和UDP区别
1. TCP是面向链接的,UDP是无连接的(即发送数据前不需要建立链接)。
2. TCP服务可靠,UDP不可靠,可能丢失信息。
3. TCP面向字节流,UDP面向报文。
4. TCP是一对一,UDP可以一对多。
WebSocket
- 支持持久性链接
- 链接完成,服务器端可以主动推送数据到客户端
web Quality(无障碍)
- 因为个别浏览器功能不全面,从而导致内容缺失。
- 解决方法:
- 优雅降级
- 渐次增强
- 使用alt属性。(图片加载不出来时显示文字)
Cookie、sessionStorage、localStorage
- 相同点: 都是保存在浏览器端,并且都是同源的。
- 不同点:
- cookie:会在http请求时自动携带,在浏览器和服务器间来回传递。存储大小很小(4K左右)
- sessionStorage:保存在本地,当关闭浏览器,sessionStorage会失效(销毁)。
- localStorage: 保存在本地,一直存在。
web worker
- 在html之中,如果执行脚本,在加载引入的js时会造成页面阻塞(即页面内容不加载,专心加载js,从而导致白屏)。
- web worker试运行在后台的js,独立于其他脚本,不会影响页面性能。
HTML语义化
- 语义化标签没有实际含义
- 语义化标签提高代码结构的阅读性
- 比如:nav表示导航条,header,footer等。
iframe
- iframe时包含一个文档的内敛框架,有些类似与组件化思想。
- 可以用iframe解决跨域问题
- 缺点:
- 会阻塞主页面的onload事件
- 搜索引擎无法解读,不利于SEO(优化)
- 影响性能
Doctype严格模式和混杂模式
- 严格模式: 排版和JS 运作模式是 以该浏览器支持的最高标准运行。
- 混杂模式:标准比较松懈。向后兼容。
http返回的状态码
- 100 continue 继续。客户端继续其请求。
- 101 switching Protocols 切换协议。服务端根据客户端的请求切换协议(只能切换到更高级协议)
- 200 ok 成功。请求成功
- 201 created 已创建。成功请求并创建了新的资源
- 202 accepted 已接受。已经接受请求,但未处理完成。
- 203 Non-Authoritative Information 非授权信息。请求成功,但返回的meta信息不在原始的服务器,而是一个副本。
- 204 no content 无内容。服务器处理成功,但是没有返回内容。
- 205 reset content 重置内容。用户终端应重置文档视图。
- 206 partial content 部分内容。服务器成功处理了部分GET请求。
- 300 Multiple Choices 多种选择。请求的资源包括多个位置。
- 301 Moved Permanently 永久移动。请求的资源已经被永久移动到新的URL。
- 302 found 临时移动。与301相同,但资源只是临时被移动。
- 303 See Other 查看其它地址。和301,302一样。使用GET或者POST请求查看。
- 304 Not Modified 未修改。所请求的资源未修改。
- 305 use proxy 使用代理。所使用的资源必须通过代理访问。
- 306 unused 已经被废弃了。
- 307 Temporary Redirect 临时重定向。和302类似,使用GET请求重定向。
- 400 Bad Request 客户端请求的语法错误,服务器无法理解。
产生原因:1. 语义有误,2.请求参数有误。 - 401 Unauthorized 请求要求用户的身份验证
- 402 Payment Required 保留,将来使用
- 403 Forbidden 服务器理解请求,但是拒绝执行。
产生原因:权限不够 - 404 Not Found 找不到地址
产生原因:请求的地址出错。 - 405 Method Not Allowed 客户端请求的方法被禁止。
产生原因:请求方法不对(应该用GET,你用POST) - 406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求.
产生原因:服务器返回的数据客户端无法接受。 - 407 Proxy Authentication Required 请求要求代理的身份认证
- 408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
- 409 ~ 417 不常用,有意可以自行了解
- 500 Internal Server Error 服务器内部错误
- 501 Not Implemented 服务器不支持请求的功能
- 502Bad Gateway 从远程服务器接收到了一个无效的响应
- 503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
- 504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
- 505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理
http常用请求头
协议头 | 说明 |
---|---|
accept | 可接受的相应内容类型(content-Type) |
accept-Charset | 可接受的字符集 |
accept-encoding | 可接受的响应内容的编码方式 |
accept-Language | 可接受的响应内容语言列表 |
accept-Datetime | 可接受的按照时间来响应内容版本 |
Authorization | 用于表示HTTP协议中需要认证资源的认证信息 |
Cache-Control | 用于指定请求/回复中是否使用缓存机制 |
connection | 客户端想要优先使用的链接类型 |
Cookie | 由之前服务器通过Set-Cookie(见下文)设置的一个HTTP协议Cookie |
content-Length | 以8进制表示的请求体长度 |
Content-MD5 | 请求体内容的二进制MD5散列值,以Base64编码的结果 |
Content-Type | 请求体的MIME类型(用于POST和PUT) |
Date | 发送该消息时的日期和时间 |
Expect | 表示客户端要求服务器做出特定的行为 |
From | 发起此请求的用户的邮件地址 |
Host | 表示服务器的域名以及服务器所监听的端口号 |
Max-Forwards | 限制该消息可以被代理以及网关转发的次数 |
Origin | 发起一个针对跨域资源共享的请求 |
Proxy-Authorization | 用于向代理进行认证的认证信息 |
Referer | 表示浏览器访问的前一个页面 |
TE | 浏览器与其接受的传输时的编码方式 |
User-Agent | 浏览器的身份标识字符串 |
Upgrade | 要求服务器升级到一个高版本协议 |
Via | 告诉服务器,这个请求是由哪些代理发出的 |
Warning | 一个一般性的警告,表示实体内容可能存在错误 |
强缓存,协商缓存
- 缓存分为两种:强缓存和协商缓存,根据相应的header内容决定。
获取资源方式 | 状态码 | 发送请求到服务器 | |
---|---|---|---|
强缓存 | 从缓存中获取内容 | 200(from cache) | 否,直接从缓存中获取 |
协商缓存 | 从缓存中获取 | 304(not modified) | 先访问服务器,进行资源比对,如果本地缓存和服务器内容一样,则调用本地缓存 |
前端优化
方法 | 具体解析 | |
---|---|---|
降低请求量 | 合并资源 | 精灵图 |
减少HTTP请求 | 强缓存,协商缓存 | |
minify/zip压缩 | 压缩图片,压缩代码 | |
webP | 压缩图片 | |
lazyLoad | 懒加载 | |
加快请求速度 | 预解析DNS | 浏览网页时,浏览器在加载网页时对网页中的域名进行解析缓存,这样在单击当前网页中的连接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。 |
减少域名数 | ||
并行加载 | 并发加载,谷歌最多支持6个。 | |
CDN分发 | CDN全称是Content Delivery Network,即内容分发网络 | |
缓存 | HTTP协议缓存请求 | 通过请求头设置cookie。 |
离线缓存mainfest | 协商缓存,请求mainfest内容时,本地缓存先和网上内容进行比对,如果不同,请求网上内容,如果相同,则直接使用本地。 | |
离线数据缓存localStorage | 强缓存,将信息保存再本地,需要时不和网上进行比对直接进行使用。 | |
渲染 | JS/CSS优化 | 优化代码。 |
加载顺序 | js写在底部,css写在头部,先外链,再本页。 | |
服务端渲染 | vue,react等MVVM。 | |
pipeline | pipeline是一套jenkins官方提供的插件,它可以用来在jenkins中实现和集成连续交付。 |
GET和POST的区别
GET | POST | |
---|---|---|
传递方式 | 通过url(?id=1) | 放在request body中 |
传递长度 | 有长度限制 | 没有长度限制 |
安全性 | 参数暴露在url | 不暴露 |
编码方式 | 只能进行url编码 | 多种编码方式 |
请求参数 | 保留在浏览历史记录里 | 不会被保存 |
TCP数据包 | 产生一个TCP数据包 | 产生两个TCP数据包 |
从输入URL到页面加载的过程
在地址栏输入一个URL,到这个页面呈现,中间的过程(简略)
-
DNS解析
- TCP连接
- 发送HTTP请求
- 服务器处理HTTP请求并返回报文
- 浏览器解析渲染页面
- 连接结束
具体过程(将依次拓展)
1.从浏览器接受url到开启网络请求线程(可展开浏览器的机制以及进程与线程之间的关系)
2.开启网络线程到发出一个完整的http请求(设计dns查询,tcp/ip请求,五层因特网协议栈等)
3.从服务器接收到请求到对应后台接收到请求(负载均衡吗,安全拦截以及后台内部的处理)
4.后台和前台的http交互(包括http头部、响应码、报文结构、cookie等)
5.单独拎出来的缓存问题,http的缓存(http缓存头部,etag,catch-control)
6.浏览器接收到http数据包后的解析流程(解析html词法分析然后解析成dom树、解析css生成css规则书、合并成render树,然后layout、painting渲染,、复合图层、GPU绘制、外联资源的处理、loaded和domcontentload等)
7.css的可视化格式模型(元素的渲染规则,如包含块,BFC,IFC等概念)
8.JS引擎解析过程(JS的解释阶段,预处理阶段,执行阶段生成执行上下文,VO,作用域链,回收机制等等)
9.其他(可以拓展不同的知识模块,如跨域,web安全,hybrid模式等)
从浏览器接收url到开启网络请求线程
这一部分展开的内容是:浏览器进程/线程模型,js的运行机制
多进程的浏览器
浏览器是多进程的,有一个主控进程,以及每一个tab页面都会新开一个进程(某些情况下多个tab会合并进程)
进程跨域包括主控进程,插件进程,GPU,tab页(浏览器内核)等等
- Browser进程:浏览器的主进程(负责协调、主控),只有一个
- 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
- GPU进程:最多一个,用于3D绘制
- 浏览器渲染进程(内核):默认每一个tab页一个进程,互不影响,控制页面渲染,脚本执行,事件处理等
多线程的浏览器内核
每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的,他有几大类子线程
- GUI线程
- JS引擎线程
- 事件触发线程
- 定时器线程
- 网络请求线程
解析URL
输入URL后,会进行解析(URL的本质就是统一资源定位符)
URL一版包括几大部分:
- protocol,协议头,譬如http,ftp等
- host,主机域名或ip地址
- prot,端口号
- path,目录路径
- query,即查询参数
- fragment,即#
- 后面的hash值,一般用来定位到某个位置
网络请求都是单独的线程
每次网络请求时都需要开辟单独的线程进行,譬如如果URL解析到http协议,就会新建一个网络线程去处理资源下载
因此,浏览器会根据解析出的协议,开辟一个网络线程,前往请求资源(这里,暂时理解为时浏览器内核开辟)
开启网络线程到发出一个完整的http请求
这一部分主要内容包括:dns查询,tcp/ip请求构建,五层因特网协议栈等
DNS查询得到IP
如果输入的是域名,需要进行dns解析成IP,大致流程:
- 如果浏览器有缓存,直接使用浏览器缓存,否则使用本机缓存,再没有的话就是用host
- 如果本地没有的话,就向dns域名服务器查询,查询到对应的ip
注意,域名查询是有可能是经过了cdn调度器的(如果有cdn存储功能的话)
而且,需要知道dns解析是很耗时的,因此如果解析域名过多,会让收评加载变的过慢,可以考虑dns-prefetch优化
dns-prefetch
-
什么是DNS Prefetch
- DNS Prefetch 是一种DNS预解析技术。当你浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在你单击当前网页中的链接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。
- 目前每次DNS解析,通常在200ms以下。针对DNS解析耗时问题,一些浏览器通过DNS Prefetch来提高访问的流畅性。
-
如何设置dns-prefetch
-
DNS Prefetch应该尽量放在网页的前面,推荐放在后面。
-
<meta http-equiv="x-dns-prefetch-control" content="on"> <link rel="dns-prefetch" href="//www.zhix.net"> <link rel="dns-prefetch" href="//api.share.zhix.net"> <link rel="dns-prefetch" href="//bdimg.share.zhix.net">
-
<!--如果不确定是http还是https连接的话建议如下写法 --> <link rel="dns-prefetch" href="//renpengpeng.com" />
-
tcp/ip请求
http的本质就是tcp/ip请求
tcp将http长报文划分为短报文,通过三次握手与服务端建立连接,进行可靠传输
三次握手的步骤:(抽象派)
客户端:hello,你是server嘛?
服务端:heool,我是server,你是client嘛?
客户端:yes,我时client
建立链接成功后,接下来就正式传输数据
然后,待断开链接时,需要进行四次挥手(因为时全双工的,所以需要四次挥手)
四次挥手的步骤:(抽象派)
主动方:我以及关闭了向你那边的主动通道,只能被动接收了
被动方:收到通道关闭的信息
被动方:那我也告诉你,我这边向你的主动通道也关闭了
主动方:最后收到数据,双方无法通信
tcp/ip的并发限制
- 浏览器对同一域名下并发的tcp链接时有限制的(2-10个不等)
- 而且在http1.0中往往一个资源下载就对应一个tcp/ip请求
- 所以针对这个平静,又出现了很多资源优化方案
GET和POST的区别
get和post虽然本质都是tcp/ip,但两者除了在http层面外,在tcp/ip层面也有区别。
get会产生一个tcp数据包,post会产生俩个。
- get请求时,浏览器会把headers和data一起发送过去,服务其响应200
- post请求时,浏览器会先发送headers,服务其响应100 continue,浏览器再发送data,服务器响应200(返回数据)。
五层因特网协议栈
从客户端发出http请求到浏览器接收,中间会经过一系列的流程。
简括就是:
- 从应用层的发送http请求,到传输层通过三次握手简历tcp/ip链接,再到网络层的ip寻址,再到数据链路层的封装成帧,最后到物理层的利用物理介质传输。
从服务器接收到请求到对应后台接收到请求
负载均衡
-
对于大型项目,由于并发访问量很大,所以往往一台服务其是吃不消的,所以一版会有若干台服务其组成一个集群,然后配合反向代理实现负载均衡。
-
用户发起的请求都指向调度服务其(反向代理服务其,譬如安装了nginx控制负载均衡),然后调度服务器根据实际的调度算法,分配不同的请求给对应集群中的服务器执行,然后调度器等待实际服务器的HTTP响应,并将它反馈给用户
后台的处理
- 一般后台都是部署到容器里,所以一般为:
- 先是容器接收到请求(如tomcat)
- 然后对应容器中的后台程序接收到请求(如java程序)
- 然后就是后台会有自己的统一处理,处理完后响应结果
- 概括下:
- 一般有的后端是有统一的验证的,如安全拦截,跨域验证
- 如果这一步不符合规则,就直接返回了响应的http报文(如拒绝请求等)
- 当验证通过后,才会进入实际的后台代码,此时是程序接收到请求,然后执行
- 等程序执行完毕后,就会返回一个http相应包
- 将这个包从后端发送到前端,完成交互
后台和前台的http交互
http报文结构
- 报文结构一般包括了:通用头部,请求/响应头部,请求/响应体
通用头部
-
这也是开发人员见过的最多的信息,包括如下:
Request Url:请求的web服务器地址 Request Method:请求方式(Get,POST,OPTIONS,PUT,HEAD,DELETE,CONNECT,TRACE) Status Code:请求的返回状态码 Remote Address:请求的远程服务器地址(会转为IP)
-
其中,Method的话分为两批次:
http1.0定义了三种请求方法:GET,POST和HEAD方法 http1.1定义了八种请求方法:GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE和CONNECT
gzip压缩
- 首先,明确gzip是一种压缩格式,需要浏览器支持才有效(一般浏览器都支持),而且gzip压缩效率很好(高达70%)
- gzip一般是由apache、tomcat等web服务器开启
长连接与短连接
首先看tcp/ip层面的定义:
- 长连接:一个tcp/ip连接上可以连续发送多个数据包,再在tcp链接保持期间,如果没有数据包发送,需要双方发检测包来维持此链接,一般需要自己做在线维持(类似于心跳包)
- 短链接:通信双方有数据交互时,就建立一个tcp链接,数据发送完成后,就断开此tcp链接
在http层面:
- http1.0中,默认使用的是短链接,也就是说,浏览器每进行一次
浏览器多进程到JS答线程
浏览器内核
- 浏览器的渲染是多线程的:
- GUI渲染线程
- 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
- 当界面需要重绘或者某种操作引发回流的时候,该线程就会执行。
- GUI渲染线程和js引起线程互斥。
- JS引擎线程
- 也成为JS内核,负责处理js脚本程序
- js引擎线程负责解析js脚本,运行代码
- js引擎一直等待着任务队列中人物的到来,然后加以处理,一个tab页中无论什么时候都只有一个js线程。
- GUI渲染和js引擎线程互斥。
- 事件触发线程
- 归属于浏览器而不是js引擎,用来控制事件循环(可以理解,js引擎自己都忙不过来,需要浏览器另开线程协助)
- 当js引擎执行代码块如setTimeOut时,(火来自浏览器内核的其他线程,如鼠标点击,AJAX异步请求等),会将对应任务添加到事件线程中
- 当对应的事件符合触发条件被触发的时候,该线程会把事件添加到待处理队列的队尾,等到js引擎的处理。
- 由于js的单线程关系,所以这些待处理队列中的事件都需要排队等待js引擎处理。
- 定时触发器线程
- 传说中setInterval与setTimeout所在线程
- 浏览器定时器并不是由javaScript引擎计数(js引擎单线程,如果处于阻塞状态就会影响计时器的准确)
- 因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待js引擎空闲后执行)
- 注意,W3c在HTML标准中规定,要求setTimeout中低于4ms的时间间隔算为4ms
- 异步http请求线程
- 在XML HttpRequest在连接后是通过浏览器新开一个线程请求
- 在检测到状态变更时,如果设置有回调函数,异步引擎就会产生状态变更事件,将这个回调再放入事件队列中,再由javaScript引擎执行。
Browser(渲染)进程和浏览器内核进程(Renderer进程)的通信进程
- browser进程收到用户请求,首先需要获取页面内容,随后将该任务通过RendererHost接口传递给Render进程。
- Renderer进程的Renderer接口收到信息,简单解释后,交给渲染线程,开始渲染。
- 渲染线程接收到请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要GPU进程来帮助渲染
- 当然可能会有JS线程操作DOM(这样可能会造成回流和重绘)
- 最好Render进程将结果传递给Browser进程
- Browser进程接收到结果并将结果绘制出来
梳理浏览器内核中线程之间的关系
GUI线程和JS引擎线程互斥
- 因为js是可以操作dom的,如果在修改这些元素属性的同时渲染界面(即js和ui线程同时运行),那么渲染线程前后获得的元素数据可能就不一致了。
- 因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程和JS引擎为互斥的关系,当JS引擎执行时GUI线程会被挂起
- GUI更新则会保存在一个队列中等到JS引擎线程空闲时立即执行
JS阻塞页面加载
- 从上述互斥可以推导出,如果JS执行时间过长,就会阻塞页面。
WebWork,JS的多线程
- 创建Woker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)
- JS引擎线程与worker线程间通过特定的方式通信(postMessage线程 API,需要通过序列化对象来与线程交互特定的数据)
- 注意,JS是单线程的,这一点的本质并未改变
浏览器渲染流程
- 解析html建立dom树
- 解析css构建render树
- 布局render树(layout/reflow),负责各元素尺寸,位置的计算
- 绘制render树
- 进行合成场景并显示
load事件和DOMContentLoaded事件的先后
- 渲染完成之后会触发load事件,这里包括两部分,load和DOMContentLoaded。
- 当DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片。(比如如果有async加载的脚本就不一定完成)
- 当onload事件触发时,页面上所有的DOM,样式表,脚本,图片都已经加载完成了
- 所以,顺序是:DOMContentLoaded -> load
css加载是否会阻塞dom树渲染
- 这里说的是头部引入css的情况
- css是由单独的下载线程异步下载的
- css加载不会阻塞DOM树解析(异步加载时DOM照常构建)
- 但会阻塞render树渲染(渲染时需等css加载完毕,因为render树需要css信息)
普通图层和复合图层
- 浏览器渲染的图层一版分为两大类:普通图层和符合图层
- 首先,普通文档流内可以理解为一个复合图层(默认符合层,里面不管添加多少元素,其实都在同一个复合图层中)
- absolute布局等,虽然会脱离普通文档流,但仍属于默认复合层
- 可以通过硬件加速的方式,声明一个新的复合图层,他会单独分配资源
- GPU中,各个复合层是单独绘制的,所以互不影响,这也是为什么某些场景硬件加速效果一级棒。
如何变成复合图层
- 把该元素变成一个复合图层,就是传说中的硬件加速技术
- 常用方法为:translate3d,translzteZ
- opacity属性/过渡动画(需要动画执行的过程才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)
- will-change属性(比较偏僻),一般配合opacity和translate使用(而且经测试,除了上述可以引发硬件加速的属性外,其他属性不会变成复合层)作用时提前告诉浏览器要变化,这样浏览器会开始做一些优化工作
- video,iframe,canvas,webgl等元素
- 其他,比如以前的flash插件
absolute和硬件加速的区别
- 可以看到,absolute虽然可以脱离普通文档流,但是无法脱离默认复合层
- 所以,就算absolute信息改变的时候不会改变普通文档流的render树,答案,浏览器最终绘制的时候,是整个复合层绘制的,所以absolute中信息的改变,仍然会影响整个复合层的绘制(浏览器会重绘它,如果复合层中内容比较多,absolute带来的绘制信息变化过大,资源消耗就会很严重)
- 硬件加速直接在另一个复合层打开,所以它的信息改变不会影响默认复合层,仅仅是影响最后的合成
复合图层的作用
- 一般一个元素开启硬件加速后会变成复合图层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能
- 尽量不要大量的使用符合图层,否则资源消耗过度,页面反而更卡
从Event Loop谈JS的运行机制
- 执行一个宏任务
- 执行过程中遇到微任务,把它加到微任务的任务队列中
- 宏任务执行完毕,立即开始执行当前微任务队列中的所有微任务
- 当前宏任务执行完毕,开始检查渲染,任何GUI线程接管渲染
- 渲染完毕后,js线程继续接管,开始下一个宏任务
- PS:Promise的polyfill于官方版本的区别在于,官方版本中promise是微任务,polyfill是宏任务
CSS
####css盒模型
- 简介:装页面上元素的矩形区域,包括IE盒子模型和标准的W3C盒子模型
- box-sizing:border-box,padding-box,content-box
- 标准盒子模型(content-box):width = content + padding + border
- IE盒子模型(border-box): width = content
- padding-box: width = content + padding
画一条0.5px的线
- 原因:0.5px的线在不同浏览器会有不同的体现。
- 方法实现:
1 meta viewport进行缩放
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
2 border-image的方式
将图片规定为包围 div 元素的边框
3 transform: scale()
同样是使用缩放
link标签和impot标签的区别
- link属于html标签,@import是css提供的
- 页面加载时,link会同时被加载,@import引用的css要等到页面加载结束后加载。
- link是html标签,没有兼容性。@import要IE5以上才能识别
- link方式权重高于@import
transition和animation的区别
他们大部分属性相同,都是随着时间改变元素的属性值。
- 区别:
1 transition需要触发一个事件才能改变属性(比如hover)。而animation不需要。
2 transition为2帧,animation是1帧。
Flex布局
flex是‘弹性布局’,用来为盒模型提供最大的灵活性。
- 使用方法
1 在父元素定义 display:flex。
2 在父元素可定义如下属性- flex-direction: 决定主轴方向。
- flex-wrap: 决定换行规则。
- flex-flow : 是前两个的缩写。
- justify-content: 对齐方式
- align-items: 交叉轴上如何对齐。
- align-content: 多根轴线的对齐方式,如果项目只有一根轴线,则不起作用。
3 在子元素可定义如下属性
7. order: 定义项目的排序顺序,数值越小,排列越前。
8. flex-grow: 定义项目的放大比例,默认为0(即不放大)。(如果所有项目的此属性都是1,则等分剩余空间,如果有一个为2,则其占据的空间是其他项目占据的两倍)
9. flex-shrink: 定义项目的缩小比例,默认为1(即如果空间不足,该项目会缩小)。(如果所有项目都为1,则空间不足会等比例缩小。如果其中一个为0,则空间不足时,为0的项目不缩小。)
10. flex-basis: 定义在分配多余空间之前,项目占据的主轴空间。默认为auto(项目本来大小)。
11. flex: 是上三项的简写。
12. align-self: 允许当个项目与其他项目不一样的对齐方式。默认为auto。
BFC(块级格式化上下文,用于清除浮动,防止margin重叠等)
- 块级格式化上下文,是一个独立的渲染区域,并且有一定的布局规则。
- 直白的来说:BFC区域就是将区域内的浮动元素计入布局之中(比如解决高度坍塌)。
- 生成BFC的元素:
1 根元素或者其他包含它的元素
2 浮动元素(元素的float不为none)
3 绝对定位元素(元素position为absolute或fixed)
4 内联块(display:inline-block)
5 表格单元格(diaplay:table-cell,HTML表格单元格默认属性)
6 表格标题(diaplay: table-caption,HTML表格标题默认属性)
7 具有overflow且值不为visible的块元素
8 display: flow-root
9 column-span:all 应当总会创建一个格式化上下文,即便具有column-span:all 的元素并不被包裹在一个多列容器中。
10 一个块格式化上下文包括创建它的元素内部所有内容,除了被包换与创建新的块级格式化上下文的后代元素内的元素。
垂直居中的方法
- margin: auto
- display:table-cell;vertical-align:middle;
- flex布局
div{
display:flex;
justify-content:center;
align-items: center;
}
关于JS动画和css3动画的差异性
- 功能涵盖面上,js比css大
- 实现重构的难度,css3更简单。
- css3可以做到自然降级。
- css3动画有天然事件支持
- csss3有兼容问题
优雅降级和渐进增强
-
优雅降级
先适配高版本浏览器。而后针对低版本浏览器逐次降低配置需求,使其可以实现基本功能。 -
渐进增强
一开始针对低版本浏览器满足基本功能。而后根据浏览器版本的提升依次提高页面交互,效果等新功能。
块元素和行内元素
-
块元素
独占一行,并且有自动填满父元素,可以设置margin和padding以及高度和宽度 -
行元素
不会独占以上,weight和height会失效,垂直方向的padding和margin会失效。 -
img元素例外,他是行元素,但是它具有weight和height等属性。
多行元素的文本内容省略
display: -webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:3;
overflow:hidden;
visivility = hidden, opacity = 0, display:none区别
-
opacity = 0
设置透明度为全透明,隐身状态,但是依然存在,不会改变页面布局,可以触发绑定的事件。 -
visibility = hidden
把该元素隐藏起来,不改变页面布局,但是绑定的事件不会触发 -
display : none
相当于直接删掉该元素。改变页面布局,绑定事件失效。
外边距折叠问题
-
问题描述:
相邻元素的margin属性重叠。 -
示例:
margin:20px;margin:30px;
如上,两个元素的margin分别是20和30.但是两个元素之间距离不是50(20+30);而是30(外边距重叠)。 -
折叠结果:
1 都为正数时,是他们之间较大的值。
2 都为负数时,是他们绝对值较大的。
3 一正一负,是他们相加的和。
position属性
- fixed(固定定位)
脱离文本流,定位位置是浏览器窗口固定位置(左上角) - relative(相对定位)
不脱离文本流,定位位置是元素本来位置。 - absolute(绝对定位)
脱离文本流,定位位置为最近的设置定位的父元素。 - static(默认定位)
默认值,没有定位。 - inherit(继承)
继承父元素的position属性。
浮动消除
1. 使用带clear属性的空元素
在浮动元素后面使用一个空元素(div),在css之中赋予 `clear : both` 属性。
2. 使用css的overflow属性
将overflow的值设为hidden或者auto。
3. 给浮动元素的容器设置浮动
不推荐,这会使整体浮动。
css选择器和优先级
css优先级高低排序:!important > 行内样式>ID选择器 > class选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
重绘和重排
- 重排
dom属性的变化(width,height等)导致浏览器需要重新计算盒子模型的排布。 - 重绘
浏览器将受到影响的部分重新绘制在屏幕上。 - 引起重排重绘的原因:
- 添加删除可见的dom
- 元素尺寸位置的改变
- 浏览器页面初始化
- 浏览器窗口大小发生改变
- 减少重绘重排的方法:
- 使用css一次性修改属性
- 使用fragment
fragment(碎片)
所谓farment,类似于组件化。
在项目中,我们可以出现要重复添加子元素(比如ul里面要添加很多个li),如果for循环添加会不停的导致重排(重绘),所以使用fragment,先全部添加到这里,而后将fragment一次性添加到ul里。
JS
前端的事件流
- 含义:从页面中接收时间的顺序。
- 三个阶段
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
添加事件的方法
-
直接在html里面通过"onclick = ‘functionName’"绑定
- 通过此方法只能添加一个事件,如果连续添加两个事件的话,第二个事件会覆盖第一个事件。
-
addEventListener(event,function,useCapture)(ie8之前使用 attachEvent())
- event:事件名称
- function:要执行的方法
- useCapture(选填):指定事件是否在冒泡或者捕获阶段执行,true——捕获,false(默认)——冒泡
-
注意事项
- 通过 addEventListener 可以添加多个事件,并且不会被覆盖。
- 如果在捕获,冒泡都添加了事件,需要删除两次。
- 如果样式中 onclick事件 和 js中的 addEventListener 都进行了使用,那么这两个都会绑定成功,且执行顺序为,先onclick 再 js绑定事件
删除事件的方法
-
如果是在html直接添加οnclick=functionName
-
document.getElementById(‘button’).οnclick=function(){};
-
如果是给方法定义名字的话,将方法名指向空方法即可即可。如下:
var textfunction = function(){ alert('123'); } textfunction = function(){}
-
如果是jquery的话,$(’#button’).removeAttr(‘onclick’);
-
-
removeEventListener(event,function,useCapture)
- 参数信息同上面。
- 如果要移除事件句柄,addEventListener() 的执行函数必须使用外部函数
防止事件冒泡或者捕获
- 防止事件冒泡: w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true。
- 冒泡的终点是windows
- 阻止默认事件: w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false。
- jquery的 return false 既可以防止事件冒泡,也可以阻止默认事件。
如何让事件先冒泡后捕获
1. 对于同一事件,监听捕获和冒泡。
2. 监听到捕获事件,暂缓执行。
3. 直到冒泡事件被捕获(冒泡完毕),执行暂缓的捕获事件
事件委托
- 含义:不在事件的发生地(比如ui下的li)上设置监听函数,而是在其父元素上设置监听函数。当点击子元素时,通过事件冒泡,父元素监听到子元素,从而进行子元素事件的触发。
- 好处:比较适合动态元素的绑定,新添加的子元素也会有监听函数和事件触发机制。
图片的懒加载和预加载
-
预加载
提前加载图片,当用户需要查看时直接在本地进行渲染。 -
懒加载
做服务端前端你的优化,减少请求书或者延迟请求数。
js的new操作符做了哪些事情
1. 新建一个空对象
2. 这个对象的原型指向构造函数的prototype。
3. 执行构造函数后返回这个对象
改变函数内部this指针的指向函数
- 通过apply和call都可以改变。
- 区别在于,apply获取的第二个参数时数组,call则是
...Array
- 通过bind改变this做用户会返回一个新的函数,这个函数不会立即执行。
Ajax解决浏览器缓存问题
1. 在ajax请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")。
2. 在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。
3. 在URL后面加上一个随机数: "fresh=" + Math.random()。
4. 在URL后面加上时间搓:"nowtime=" + new Date().getTime()。
5. 如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。
浏览器渲染原理
1. js引入
2. style样式计算
3. layout布局计算
4. paint绘制填充样式
5. composite渲染层合并
js的节流和防抖(高性能滚动csroll以及页面渲染优化)
- 含义:再绑定scroll,resize这类事件时,当他发生,触发的频率非常高。间隔很近。如果此类函数涉及大量计算,会造成浏览器的掉帧。cpu使用率增加,影响用户体验。所以出现了节流和防抖。
- 防抖
在一定时间内,规定事件被触发的次数。 - 节流
节流保证函数在规定时间内,必定会触发一次。
js中的垃圾回收机制
1. 标记清除
var a="hello world";
var b="world";
var a=b;
如上,这时,系统会释放 “hello world” 的内存。
2. 引用计数
给每个值一个引用的次数,当声明一个变量,并将一个引用类型的值赋值给该变量,这个值的引用次数+1,反之-1.当引用次数为0,系统会清理该变量。(会出现内存泄漏)
eval
将对应的字符串解析成js并执行。(很少使用,消耗性能)
js判断类型
1. typeof()
typeof()只能判断基本类型,array和object都会返回object。
2. instanceof()
3. object.prototype.tostring()
4. object.is()
ES6新出
数组去重
1. indexof循环去重
2. ES6 SET去重
Array.from(new Set(Array))
闭包
-
简单来说,闭包 = 函数 + 函数能够访问的自由变量。
-
含义:有权访问另外一个函数作用域中的变量。
闭包时函数的局部变量集合,在一个函数内定义另一个函数就会产生闭包。 -
用途
- 匿名自执行函数
2.结果缓存
3.封装
- 匿名自执行函数
性能优化
- 减少HTTP请求
- 使用内容发布网络(扔到服务器上,使用的时候进行加载)
- 添加本地缓存
- css样式表放顶部,js放底部(或者defer)
- 避免使用css表达式
- 使用外部js和css
- 图片懒加载
- 避免重定向
继承实现的几种方式
1. 原型链继承
将父类的实例作为子类的原型。
优点: 易于实现
缺点: 无法多继承,无法向父类够惨函数传参
2. 构造继承
使用父类的构造函数来增强子类实例,即复制父类的实例对象给子类。
优点: 可以实现多继承,可以向父类传参
缺点: 影响性能
3. 实例继承
为父类实例添加新特性,作为子类实例返回。
优点:实例继承的特点时不限制调用方法,不管是new子类()还是子类() 返回的对象具有相同的想过。
缺点: 不支持多继承
4. 拷贝继承
优点: 支持多继承
缺点: 效率低,内存占用高
5. 组合继承:
6. 寄生组合继承
symbol
sumbol是ES6新增的属性,为对象加标识,使其唯一。
promise
promise是一个对象,解决异步状态的时候使用。
- 特点:
- 对象状态不受外界影响,有三种状态,pending(进行中),fulfilled(成功),rejected(失败)
- 一旦状态改变,就不会再变。
promise+Generator+Async的对比
- 他们三者都是解决异步现象的。
- promise上面有介绍。
- generator函数,是可以分段运行的函数体,相比较于promise,解决连续异步时减少了代码冗余。
- Async 时generator的语法糖。ES7语法。
setTimeout和Promise的执行顺序
如下问题:
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function(resolve, reject) {
console.log(2)
for (var i = 0; i < 10000; i++) {
if(i === 10) {console.log(10)}
i == 9999 && resolve();
}
console.log(3)
}).then(function() {
console.log(4)
})
console.log(5);
输出答案为2 10 3 5 4 1
原因:
- promise新建之后立即执行,
- then在promise函数同级任务执行完执行,
- setTimeout 不是真的立即执行,所以没有then执行快。
如何获得对象上的属性
1. for(let i in obj)依次访问对象中可枚举的内容
2. object.keys():返回数组,包含所有可枚举内容
3. object.getOwnPropetryNames:返回一个数组,包含不可枚举属性。
箭头函数和function的区别
- 箭头函数没有绑定自己的this,在箭头函数中调用this,沿作用域链向上寻找,找到最近的一个this来使用。
this关键字
- this指向的永远是一个对象
- 在方法中,this表示该方法所属的对象
- 如果单独使用,this表示全局对象
- 在函数中,this表示全局对象
- 在事件中,this表示接受事件的元素
- 箭头函数不会生成新的this,箭头函数里的this会自动寻找最近的this。
- 类似call(),apply()可以将this引入到任何对象
箭头函数(注意点)
- 函数体内的this,是定义时所在的对象,而不是使用时所在的对象
- 不可以当成构造函数,也就是说,不可以使用new命令,不然会报错
- 不可以使用arguments都西昂,该对象在函数体内不存在。如果要用,用rest参数代替。
- 不可以使用yield命令,因此箭头函数不能用作Generator函数
解构赋值
- 解构赋值时浅拷贝,即如果一个键的值时复合类型的值(数组,对象,函数),那么解构赋值拷贝的是这个值的引用,而不是副本。
GET和POST区别
- GET产生一个TCP数据包;POST产生两个TCP数据包。并不是所有浏览器都会在POST中发送两次包,firfox只发送一次。
- GET在浏览器回退时是无害的,而POST会再次发送请求。
- GET是表单提交的默认方法。
- GET请求参数会被完整保留在浏览器历史记录里面,POST不会。
- GET传递没有POST安全,而且GET传输数据的大小远比POST小的多。
说一声SEO(搜索引擎优化)
- 对自身网页而言:
- 网页头部添加TDK,即title,description,keyword这三个标签
- 使用语义化的标签。如main,article,header,footer,nav,aside等。语义化代码会让搜索引擎容易理解网页。
- 重要的内容不要放在js代码里,搜索引擎不会爬取js代码
- 提高网站性能
- 其他的一些方面
- 使用https协议
- 网址静态化,短网址,伪静态
- 全站地图sitemap,即告诉搜索引擎怎么爬取你的网址
- 提交百度收录,添加tobots机器人(一个txt文件,告诉八度引起想让他爬什么,不能爬什么)
提高网站性能
- 减少http请求(使用websockets,减少重定向等)
- 使用压缩,webpack打包等
- css放最上面,js放最下面(js放下面防止出现空白网页,js可能阻碍渲染)
- 懒加载(vue的路由懒加载,图片懒加载等)
- nginx反向代理
- 使用cdn
Let 和 Const对比
- let生命的变量具有块级作用域
- let声明的变量不能在通过window.变量名进行访问
- 形如for(let x)的循环每次迭代都会为x创建新的绑定
如何实现跨域
- jsonp
和ajax不同,请求script,动态插入。 - CORS
服务器端设置Access-Control-Allow-Origin - iframe
iframe解决跨域,不推荐 - proxy代理
使用代理服务器,实现数据转发
VUE
vue生命周期
1. boefocreated (创建之前)
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
2. created(创建,生成data,可以进行data的修改,一般在这里发起ajax请求获取数据)
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
3. beforemount(挂载之前)
在挂载开始之前被调用:相关的 render 函数首次被调用。
4. mounted(挂载,挂载DOM,可以进行DOM操作,一般在这里进行DOM相关操作)
el 被新创建的 vm.$替换,并挂载到实例上去之后调用该钩子。如果实例挂载了一个文档内元素,当被调用时el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
5. beforeupdate (数据更新之前)
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
6. update(数据更新)
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
7. beforeDestory(销毁之前)
实例销毁之前调用。在这一步,实例仍然完全可用。
8. destroyed(销毁)
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
v-for的时候为什么需要绑定key值
- key的作用主要是为了高效的更新虚拟DOM。
- VUE的虚拟DOM的Diff算法有关系。(比如在 ABCDE 中的B和C之间插入E)
- 如果没有key,系统会将C更新为F,D更新为C,E更新为D,然后在最好插入E。浪费效率。
- 如果由key,Diff算法可以正确的识别此节点,找到正确的位置进行插入。
VUE虚拟DOM
-
虚拟DOM就是为了解决浏览器性能问题而被设计出来的。
-
案例解析:
- 若一次操作中有10次更新DOM的动作,操作真实DOM,会造成连续多次的更新DOM元素,从而影响性能。
- 虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。
-
好处:页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。
VUE获取DOM元素
- 在vue之中, 原生html获取DOM(不推荐)
mounted(){//这里必须是mouted钩子
//document.querySelector('#footer-box-title') 原生html获取DOM
this.title = document.querySelector('#footer-box-title');
this.title.style.color = "#ff0000";
}
- 通过ref获取
//给标签设置ref值,
<button ref="btn">获取ref</button>
//通过refs获取
this.$refs.btn.style.backgroundColor="#ff0000"
VUE之中method属性方法可以实现computed属性的功能,为什么还要用computed?
- computed是有缓存的,当页面多次调用时,会进行对比,如果数据没有发生改变,将直接渲染。
- method方法没有缓存,调用一次便会执行一次,影响性能。
v-on详解
事件句柄(可绑定事件)
属性 | 监听事件 |
---|---|
onabort | 图像加载被中断 |
onblur | 元素失去焦点 |
onchange | 用户改变域的内容 |
onclick | 鼠标点击对象 |
ondblclick | 鼠标双击对象 |
onerror | 当加载文档或图片时出现错误 |
onfocus | 元素获得焦点 |
onkeydown | 某个键盘的键被按下 |
onkeypress | 某个键盘的键被按下或按住 |
onkeyup | 某个键盘的键被松开 |
onload | 某个页面或图像被加载完成 |
onmousedown | 某个鼠标按键被按下 |
onmousemove | 鼠标被移动 |
onmouseout | 鼠标从某元素移开 |
onmouseover | 鼠标被移到某元素之上 |
onmouseup | 某个鼠标按键被松开 |
onreset | 重置按钮被点击 |
onresize | 窗口或框架被调整尺寸 |
onselect | 文本被选定 |
onsubmit | 提交按钮被点击 |
onunload | 用户退出页面 |
v-on 修饰符
修饰符 | 说明 |
---|---|
.stop | 调用event.stopPropagetion() |
.prevent | 调用event.perventDefault() |
.capture | 添加事件监听器时使用capture(捕获)模式 |
.self | 只当事件从监听器绑定的元素本身触发时才触发回调 |
.{keyCode | keyAlias} | 当事件从特定键触发的时候才会触发回调 |
.native | 监听组件根元素的原生事件 |
.once | 只触发一次回调 |
.left | 只当点击鼠标左键的时候触发 |
.right | 只当点击鼠标右键的时候才触发 |
.middle | 只当点击鼠标中键的时候才触发 |
.passive | 以{passive:true}模式添加监听器,(进行默认事件),该方法和pervent冲突。(如果一起使用,编译器会直接报错) |
keyCode值和对应按键
按键 | keyCode |
---|---|
0-9 | 48-57 |
a-z/A-Z | 65-90 |
F1-F24 | 112-135 |
BackSpace(退格) | 8 |
Tab | 9 |
Enter(回车) | 13 |
Caps_Lock(大写锁定) | 20 |
Space(空格键) | 32 |
Left(左箭头) | 37 |
up(上箭头) | 38 |
Right(右箭头) | 39 |
Down(下箭头) | 40 |
VUE为常用按键设置了别名
别名 | 按键 |
---|---|
.delete | delete(删除)/BackSpace(退格) |
.tab | Tab |
.enter | Enter(回车) |
.esc | Esc(退出) |
.space | Space(空格键) |
.left | Left(左箭头) |
.up | Up(上箭头) |
.right | Right(右箭头) |
.down | Down(下箭头) |
.ctrl | Ctrl |
.alt | Alt |
.shift | Shift |
.meta | windows中为window键,mac中为command键 |
-
使用Element-UI时,需要使用.native修饰符,如:@keyup.enter.native="dosth"
-
Vue中支持组合写法,如:@keyup.alt.67=”dosth” 为 Alt + C
通过v-if切换input等组件时会出现组件复用问题
- vue会尽可能的优化性能,所以进行了组件的服用,不过需要变换的id,class都会进行更改,只是input里面的内容不会被清空。
- 防止复用的方法:为不被复用的组件设置不同的key。
在前端JS之中,没有重载,如果定义一样的名字,会进行覆盖,但是我们可以通过方法实现类似重载的效果。
父子组件之间的传值调用等方法
传值 | 调用方法 | |
---|---|---|
父传子 | prop | 使用ref获取子组件并调用方法 |
子传父 | 1.vuex 2.this.parents.data | 1.使用emit来调用方法 2.使用this.parents.methods调用 |
兄弟组件 | VUEX,BUS | |
跨级组件 | VUEX,attrs,listeners,provide,inject |
关于双向绑定
vue是响应式的,如果vue中data上有一个obj对象,对一个属性没有进行声明,那么给这个属性赋值的时候,是非响应式的,不会引起重新渲染。html不会发生变化,forceUpdate可以帮助我们处理。
this.$forceUpdate()
但是不建议这么做,因为对性能会有影响。
建议使用的方法是set方法。
this.$set(this.data,'show',true)
ps:this.$nextTick()对于这类情况不产生作用。因为双向绑定依然是没有进行绑定的。
路由相关
hash | history | |
---|---|---|
样式 | https://www.word.com#id | https://www.word.com/id |
特性 | 1.客户端的状态(向服务端发送请求的时候,hash部分不被发送) 2.会在浏览器访问历史上增加一个记录,可以使用浏览器的前进后退 3.hashchange事件来监听 | 1.需要后台进行对应配置,不然刷新会404 2提供了对应的api来加入到路由 |