网上看到的字节面试题,蚍蜉撼树写下答案

前言

今天早上起来打算继续写作作字节面试题系列的文章,在get了排版技巧后(绯红主题真香),以前的文章就变得不忍直视了,怪不得阅读量不高。css

这个时候确定有小伙伴会嘀咕:不会觉得你排版好看阅读量就高了吧?并且你这排版也很差看。哈哈,慢慢来嘛,目前Yiming仍是个小白,只要心态好,阅读低不了!html

每篇的前言(废话)部分就到这里,把当下做为新的起点,冲冲冲!前端

猛戳这里查看原文webpack

1px的问题能够如何去解决【尽量地多说】

出现1px的缘由是设计图上的1px指的是设备像素,而不是CSS像素。DPR这个视网膜屏幕的概念最早是由苹果公司提出,计算公式:DPR = CSS像素 / 设备像素。程序员

以IPhone 6为例,DPR = 750 / 375 = 2,在DPR为2的屏幕下,1px的物理像素会以2px渲染出来,这里给几个思路:web

  • 咱们能够用0.5px的CSS像素;
  • 修改viewport
  • 伪类+scale,先给伪类设200%的宽度,而后再transform:scaleY(0.5)

最有效的是,无论设计师怎么催咱们,就是不改!哈哈,开个玩笑,这个问题以前了解的比较少,若是Yiming在工做中碰到了这种状况,Yiming会和设计师多沟通下,若是沟通无果,那就只能改了,哭唧唧~面试

(设计师:看到没?只要逼着他改,他就会和Yiming同样改的,因此逼就完事了!)算法

Less和CSS的区别,Less的函数有了解过么

less是css预处理器,可让咱们写出易于维护的css代码,不过Yiming在工做中只用它来申明过全局变量,这里就丢个官网的连接吧:http://lesscss.cn/functionsjson

在浏览器输入一个URL的总体过程是怎么样的

这个问题通常都会问,由于每个步均可以进行延伸,也不知道是哪一个老哥想出来的鬼才面试题,下面是个人理解:canvas

  1. 当咱们在浏览器地址栏按下键盘的时候,浏览器就会启动一个算法去书签栏和历史记录中按照咱们输入的字母进行筛选、展现一个咱们可能会访问的URL

  2. 当咱们选定了URL按下回车时,浏览器就会开始构建请求行,而后检测这个域名是否合法,若是合法就将此任务给网络请求线程

  3. 构建好请求行后就会去检测强缓存是否有效(这个步骤不会发送网络请求),若是无效,就会开始调用DNS协议进行域名解析,若是以前访问过这个URL,那么浏览器会把DNS解析后的IP地址保存下来,下次访问就直接命中(大概能够节约50~200ms),若是没有就须要去网络运营商或者DNS服务器上寻找

  4. 拿到DNS解析的IP地址后,就会构建HTTP请求,开始TCP三次握手创建稳定连接:客户端向服务器发送一个SYN(同步序列编码),服务端收到后返回一个新的SYN + ACK(在第一个SYN上作计算后生成的回复消息),客户端收到后回复一个ACK,三次握手创建完毕。为何是三次?两次太少,四次太多

  5. 创建好三次握手后,TCP协议为了传输方便,会将HTTP报文切割并编码成一个个数据包,随后转交给网络层

  6. 网络层拿到这些数据包后,经过IP地址,配合ARP协议反查出MAC地址,开始传输数据 服务器收到这些数据后,将在TCP传输层协议中被分割的报文还原成完整的,这个时候通常会校验是否有权限、是否设置了缓存以及是否过时等。若是设置了协商缓存,那么会返回304状态码通知浏览器使用协商缓存(这里能够把协商缓存的字段也说下),不然开始响应。响应完毕后,服务器会判断Connection字段是否为keep-alive(在HTTP 1.1中是默认值),不是则断开

  7. 接下来就是浏览器开始解析请求到的文件,首先调用GUI线程并行解析HTML和CSS文件,对HTML文件使用标记化和建树算法,根据文件中设置的<!DOCTYPE>标准来生成DOM树,对CSS文件进行格式化和标准化生成CSSOM树,最后合并成合成树。注意HTML和CSS文件解析是互不影响的,可是会影响最后的合成树生成的速度,因此CSS文件中不要放@import,它老是在CSS文件解析完毕后再去加载对应的资源

  8. 另外GUI线程和JS线程是互斥的,当解析到HTML文件中的script标签时,就会挂起GUI线程,从而阻塞渲染,因此script标签中不要写async,它老是异步加载,而后当即执行,但你能够写defer 拿到合成树后,为了提升渲染效率,由于复杂的图层老是会由GUP单独绘制(GPU加速),不会影响其余的图层,因此开始建立图层树。普通文档流能够算是复杂图层,除此以外absolute、transform、opacity、canvas等元素都能造成复杂图层,因此说动画最好放在absolute等元素上、用transform代替left/top

  9. 浏览器将这些图层的绘制生成一个个绘制指令,而后交给合成池去进行绘制,生成图块和位图,最后显示出当前的页面

这个答案还能够更详细,兄弟萌,能够下去本身再补充下哦!

描述一下浏览器页面渲染的过程

能够看上一题

浏览器白屏是什么致使的

我这里就从两个方面来答吧:

  • 网络阶段,好比第一次访问没有缓存DNS对应的IP地址,网站设置了301跳转等等

  • 渲染阶段。咱们知道浏览器在拿到文件后会将它们解析成对应的DOM和CSSOM,这里有两个方面:第一个方面,因为浏览器的GUI渲染线程和JS线程互斥,因此碰到script标签就会先对JS文件进行解析,从而阻塞渲染,因此要注意书写的位置;第二个方面,若是CSS文件中有@import,那么它会在CSS解析完毕后再进行加载,一样会形成阻塞。

还能够继续说下去~

浏览器存储Cookie、localStorage、sessionStorage的区别

Cookie

因为HTTP是无状态的应用层协议,致使服务器没法记住客户端用户的操做,而Cookie主要用来记录用户的身份信息,它的大小只有4kb,无论服务端是否须要用到它,它老是被来回的传递(但不支持跨域),它和HTTP缓存同样,也能够经过设置max-age和expires字段决定过时时间。

在安全上,因为JS脚本能够读取Cookie,因此咱们得经过Set-Cookie中设置httpOnly禁止JS读取,预防XSS攻击。除此以外,不该该用Cookie传递敏感信息。

因此能够看出Cookie主要是用来维持状态,而不是作本地存储的

localStorage

H5中新提出的Web存储技术,大小是5MB,远大于Cookie体积。因为保存在浏览器端,因此咱们能够直接经过API调用:

  • 存:localStorage.setItem("key","value")
  • 取:localStorage.getItem("key")

它的生命周期是永久,除非手动清除。应用场景上,咱们能够用它来保存图片这种内容稳定的资源

sessionStorage

和localStorage同样,不只都是H5提出的Web存储技术,并且用法和空间大小也极为类似,最大不一样的地方有两点:

  • sessionStorage的生命周期是当前标签页关闭
  • 没法跨标签页访问,也就是Tab

相同点是它们三个都是存在客户端,且没法跨域

感兴趣能够看这位大佬:https://juejin.cn/post/6844903812092674061

Cookie如何进行设置的,JS能改变哪些值

要搞清楚这个问题,咱们得先去看看Cookie它保存的有哪些值?

name

这个就是Cookie的name,所以同域名下的Cookie会被name值相同的覆盖掉

value

由于Cookie是以key-value的形式存储的,因此这里的value就是对应的属性值,且必须通过URL编码

domain

这个就指的是域名,这里有一个小知识点,只有域名彻底相同才能够共用一个Cookie,好比,www.manice.com和play.mdnice.com是没法共用一个Cookie的,不过能够经过设置domain为顶级域名就能够公用了,具体的你们能够百度,一搜一大把

HttpOnly

这个想必你们比较的熟悉,预防XSS攻击的,设置为true后,JS脚本就没法读取到Cookie里面的值

还有一些诸如path、secure等就不一一赘述了,因此JS脚本能读到Cookie,那就能够对其进行更改

描述一下浏览器缓存

这个部分有不少内容能够说:

强缓存

不须要发送HTTP请求,只会构建请求行,根据HTTP协议的不一样分为两种:

HTTP 1.0中的Expires,过时时间,潜在的问题是服务器时间和客户端时间不一致

HTTP 1.1中的Cache-Control,能够设置max-age来设置缓存生效时间,超过期间段就须要从新发起请求,关于Cache-Control还有不少属性:

  • max-age:资源最大有效时间
  • no-cache:不缓存,但实际上每次在请求静态资源的时候会向服务端发送一个过时认证请求,须要配合ETag或者last-modified
  • no-store:始终都去服务端请求最新资源,优先级最高
  • private/public:在请求资源的时候,可能会通过一些CND、Nginx中间代理服务器,若是设置了private,在max-age过时的状况下,即便中间服务器提示可使用本地缓存资源,依然会向原服务器发送请求,而public相反
协商缓存

须要请求头中添加tag,服务器根据tag来判断是否使用缓存,因此被称为协商缓存。tag分为两种Last-Modified和ETag

  • Last-Modified

最后修改时间。在第一次请求完毕后,服务器给浏览器返回的响应头里会带有Last-Modified,浏览器在下一次请求的时候会携带If-Modified-Since,表示服务器资源最后修改时间,最后进行相应的操做。不然返回304,但只能以秒为单位,因此不够精准(不在乎这几秒的差距也OK)

  • ETag

ETag是给当前的文件资源添加惟一的文件标识,只要内容有改动就值就会变。服务器会将其加在响应头中,浏览器会在下次请求的时候将其做为If-None-Match字段的内容发送给服务器。服务器根据值作不一样的操做

  • 二者对比:

ETag优先级比Last-Modified高,由于它能够精确的判断是否须要更新。虽然性能不如Last-Modified

缓存位置

强缓存和协商缓存的位置按优先级排列分别是:

  • Service Worker

借鉴了Web Worker,让JS运行在主线程以外,脱离了浏览器窗体,因此也没法访问DOM,但能够帮助咱们实现离线缓存、网络代理等功能

  • Memory Cache

内存缓存。存取最快,但寿命很短

  • Disk Cache

硬盘缓存。存取慢,寿命长,空间也大,若是缓存内容过大,那么就用这种方法,不然是内存缓存

  • Push Cache

推送缓存。HTTP 2.0的内容,只存储在session中,当会话结束后就会被释放,并且在Chrome浏览器中只会保存5分钟

  • Cookie策略机制

它是一个用于服务端和客户端之间的认证,当服务端返回了这个cookie,那么每次请求这个域名下资源的时候(即便是二级域名也会带),都会带上这个cookie,且若是不设置cookie的过时时间,只要关闭了浏览器,cookie就会失效,因此能够经过设置max-age

另外出于安全考量,咱们须要给cookie设置一个httpOnly,设置secure cookie,只有在https服务下才会在application/cookie中写入cookie

反作用

有的时候缓存反而碍事,由于浏览器会对html文件进行一个自动的缓存,因此咱们最好在进行联调的时候设置一个:

<meta http-equiv='Cache-Control' content='no-cache' />
复制代码
总结

首先会经过Cache-Control判断可以使用强缓存

若是不能够则使用协商缓存,服务器经过判断请求头中的If-Modified-Since和If-None-Match判断资源是否更新?

  • 更新:返回200以及最新内容

  • 无更新:返回304以及使用缓存中的资源

较为稳妥的实践

先说说强缓存和协商缓存的问题点:

  • 强缓存:设置了cache-control字段,那么若是服务器的资源忽然更新了,用户看到的内容就不是最新的了,固然你要是能接受那就OK

  • 协商缓存:每次都会去询问一次服务器资源是否有更新,仍是会形成必定的资源浪费,毕竟咱们是追求极致的程序员

那么最好的方案是配合Webpack:

  1. HTML文件:使用协商缓存
  2. CSS、JS和图片:使用强缓存,而且给文件名都附带上Hash值

contentHash的讲究

当css文件hash改变的时候,js文件hash也会随之改变,因此咱们能够在webpack打包的时候使用contentHash

你们也能够自行到掘金查看更为详细的解法

HTTP的状态码有哪些

这里讲下Yiming比较经常使用的吧

1XX
  • 100:等待后续处理,好比POST请求发送大实体数据时
2XX
  • 200:请求成功处理,且返回了请求的数据
  • 204:请求成功处理,但没有返回任何实体部分
3XX
  • 301:永久重定向跳转(重定向可能会下降网页的打开速度)
  • 302:临时重定向跳转(由于是临时跳转,因此也不会进行缓存)
  • 304:没有资源更新,熟悉缓存的小伙伴应该知道这个状态码
4XX
  • 401:须要认证,前端鉴权中会用到这个状态码
  • 403:对当前资源没有访问权限
  • 404:没有请求的资源
5XX
  • 502:服务器正常,但发生未知错误。当用户帐号或密码填错时,会出现这个状态码
  • 503:服务器处于停机维护中,也就是没有开启

更多状态码可看:

  • https://juejin.cn/post/6844903519447678990

HTTP的请求头包含什么

哈~又是一个很长的答案,这里讲下Yiming经常使用的吧:

  • Connection:表示是否须要长链接。在HTTP/1.1中默认为keep-alive,能够设置close字段关闭
  • Cache-Control:表示缓存机制,它有多个字段,如no-cache、no-store等等
  • Cookie:用来作状态存储,解决HTTP协议中没法保存用户状态的弊端,无论请求中是否须要,都会将保存在当前域下的全部cookie传递给服务器
  • 还有协商缓存相关的,If-None-Match、If-Match、If-Modified-Since、If-Unmodified-Since
  • Referer:请求来源,能够用来预防CSRF攻击
  • Upgrade:指定某种协议,好比指定使用Websocket协议通讯

更多:https://segmentfault.com/a/1190000006689767

解决跨域的方法有哪几种

也是一个有不少答案,我在工做中只用到过CORS和Nginx反向代理,这里就不赘述了,掘金一搜一大把~不嫌弃的话也能够看看我这篇:

  • https://juejin.cn/post/6844904148022870023

描述一下JSONP的原理

由于script中的src属性不受同源策略影响,因此咱们能够先在全局定义一个回调函数,而后在Ajax请求时,将函数名做为参数传递,当服务器返回数据到客户端时就会以前咱们以前定义好的回调函数,这里给一下代码:

// 接收三个参数,要发起请求的URL、请求的参数、回调函数
function jsonp({ url, params, cb }) {  // 这里是拼接参数的方法  let createUrl = () => {  // 申明一个字符串  let dataStr = ''  // for...in循环遍历参数  for (let k in params) {  // 进行拼接  dataStr += `${k}=${params[k]}&`  }  // 最后将回调函数也加上去  dataStr += `callback=${cb}`  // 返回最终的结果  return `${url}?${dataStr}`  }  // 返回一个Promise对象  return new Promise((resolve, reject) => {  // 在页面上建立script标签  let script = document.createElement('script')  // 将script标签中的src属性设置为上面函数返回的参数  script.src = createUrl()  // 将script标签插入到body中  document.body.appendChild(script)  // 添加回调  window[cb] = data => {  // 成功的回调,会将咱们要请求的参数做为参数传入  resolve(data)  // 执行完毕后移除script标签  document.body.removeChild(script)  }  }) } 复制代码

描述一下CORS的过程

CORS这个是后端进行处理的,但前端也得懂点。CORS翻译过来就是Cross-Origin-Resource-Shared,即跨域资源共享,它分为简单请求和复杂请求,复杂请求又会多发一次预检请求,不过预检请求也不必定就是安全的,依然要注意CSRF攻击

服务端设置了Access-Control-Allow-Origin,也就是资源控制容许源(感受翻译过来怪怪的),就会开启CORS,每次浏览器在发送请求的时候都会带上Origin字段,它由协议、域名和端口号组成,如:

Origin: https://127.0.0.0:8080
复制代码

而后让服务端判断是否能够给Origin这个源返回数据。这里没有详细的介绍CORS,篇幅有点长,因此就给你们指一条路:

  • https://juejin.cn/post/6844904094973296654

写在最后

到这里就结束了,感谢你们的观看。虽而后面还有不少的题目没写,但考虑到那些题目的含金量比较大,因此想从源码的角度去进行解答(篇幅天然也不会有这么长啦~)

若是各位发现答案有误,恳请留言指出,不能误导更多的人

本文使用 mdnice 排版

相关文章
相关标签/搜索