腾讯前端面试-校招-2019

本文最后更新于:2021/02/14 , 星期日 , 22:13

前言

最近在准备笔试面试,所以又搁置了博文更新计划。强迫自己更新文章,所以来一个腾讯的面经。将之前翻车的答案都更正为正确答案。

一面

一面的机会纯属偶然获得,和笔试相隔了很久,早已经忘记了腾讯的事,都已经愉快的放飞自我了,各种吃喝玩乐,突然之间就收到了腾讯的一面,一天都很亢奋。

输入 url 到显示的过程

  1. 首先浏览器有五大线程:渲染线程,JS 线程,事件线程,网络线程,定时器线程
  2. 输入 URl 后会进行解析.然后开辟一个网络线程,请求资源。从应用层发送的 http 请求,到传输层通过三次握手建立 tcp/ip 链接,再到网络层的 ip 寻址,然后再到数据链路层的封装成帧,最后到物理层的利用物理介质传输。
  • DNS 查询:如果浏览器有缓存,则直接使用浏览器缓存否则使用本机缓存,再没有就是用 host.如果没有缓存就向 dns 域名服务器查询,查询到对应 ip
  • 三次握手 seq->ack seq ack
  • 四次挥手
  1. 从服务器接受到的请求到对应后台收到请求,后台进行处理.一般有的后台有统一性验证,安全拦截,跨域验证之类的.如果这一步不符合规则,就直接返回了相应的 http 报文,如果通过,才会进行实际的后台代码,此时是程序接收到请求,然后执行.等程序执行完毕后,就会返回一个 http 响应包.然后将这个包从后端发送到前端,完成交互。前端后端交互时 http 报文作为信息的载体.
  2. 然后开始前端渲染
  3. 浏览器解析 html,构建 dom 树 过程:字节数据 字符串 tokens nodes dom
  4. 解析 css 生成 css 规则树 过程:字节数据 字符串 tokens nodes cssom 在这过程中浏览器会确定下每一个节点的样式.
  5. 合并 dom 树和 css 规则,生成 render 树 计算 css 样式,渲染树只会包括需要现实的节点和这些节点的样式信息
  6. 布局 render 树
  7. 绘制 render 树
  8. 浏览器会将各层的信息发送给 GPU,GPU 将各层合成显示在屏幕上
  9. 遇到 script 标签时,会执行并阻塞渲染:因为浏览器渲染和 js 执行公用一个线程,而且这里必须是单线程操作,多线程会产生渲染 DOM 冲突.等 script 标签完成后,浏览器会继续渲染.这也可以解释为什么 js 放在 html 底部,JS 放在底部可以保证让浏览器优先渲染完现有的 HTML 内容,让用户先看到内容,体验好。另外,JS 执行如果涉及 DOM 操作,得等待 DOM 解析完成才行,JS 放在底部执行时,HTML 肯定都解析成了 DOM 结构。JS 如果放在 HTML 顶部,JS 执行的时候 HTML 还没来得及转换为 DOM 结构,可能会报错。

linux 指令

指令有点多,问我的我也记不太清了 2333,多看看鸟哥的私房菜

同源策略怎么回事?以及如何实现跨域请求

同源策略目的是为了保护用户的信息安全,防止恶意的网站窃取数据,比如 A 网站的 cookie,B 网站就不能使用,同源指的是协议,url,端口全部一致。实现跨域的方法有多种。
同源策略限制了以下三种行为:

  • Ajax 请求不能发送,所以就出现了跨域
  • DOM 无法获得
  • cookie,localstroge,indexDB 无法读取
    解决 cookie 不能共享,可以设置相同的 document.domain 就可以.
    跨域解决方案:
  1. JSONP:JSONP = json + padding 填充式 json 利用的是动态创建 script 标签,向服务器请求 json 数据,服务器收到请求后,服务器将传回来的数据放在指定名字的回调函数中传回来,这样就可以实现跨域访问。简单实用,老旧浏览器都适用,但是只支持 GET 请求。
  2. 配置 nginx 代理
  3. CORS:服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

用什么版本控制器

git。git 指令推荐看看:廖雪峰 Git 教程

闭包是什么?闭包会带来什么问题?

当执行上下文中创建的函数执行时,如果访问了执行上下文中变量对象中的值,闭包就会产生
JavaScript 拥有自动的垃圾回收机制,关于垃圾回收机制,有一个重要的行为,那就是,当一个值,在内存中失去引用时,垃圾回收机制会根据特殊的算法找到它,并将其回收,释放内存。函数的执行上下文,在执行完毕之后,生命周期结束,那么该函数的执行上下文就会失去引用。其占用的内存空间很快就会被垃圾回收器释放。可是闭包的存在,会阻止这一过程。
闭包副作用会造成内存泄露,正面作用利用闭包可以实现块级作用域,IIFE,模块化

性能优化

性能优化可以分为两种:减少页面体积,提升网络加载 和 优化页面渲染

  • 减少页面体积,提升网络加载
    • 静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)
    • 静态资源缓存(资源名称加 MD5 戳)
    • 使用 CDN 让资源加载更快
  • 优化页面渲染
    • CSS 放前面,JS 放后面
    • 懒加载(图片懒加载、下拉加载更多)
    • 减少 DOM 查询,对 DOM 查询做缓存
    • 减少 DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)
    • 事件节流
    • 尽早执行操作(DOMContentLoaded)
    • 使用 SSR 后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS 模板渲染页面 HTML 的时间

为什么操作 DOM 慢

因为 DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当通过 JS 操作 DOM 的时候,其实这个操作涉及到了两个线程之间的通信,然后会带来一些性能上的损耗。操作 DOM 次数一多,也就等同于一直在进行线程之间的通信,并且操作 DOM 可能还会带来重绘回流的情况,所以也就导致了性能上的问题。

如何阻止事件冒泡

dom 标准事件流的触发的先后顺序为:先捕获再冒泡.事件捕获:通俗的理解就是,当鼠标点击或者触发 dom 事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。事件冒泡:与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。使用 stopPropagation()阻止事件冒泡.使用 preventDefault()阻止默认行为

二面

二面和一面相隔了三天,不过一面面完的下午就变成了复试状态,截止写此文为止还没消息,一直是复试状态。感觉要加面。

React 有哪些优点

  1. 使用了虚拟节点,性能好
  2. 因为强调只从 this.props 和 this.state 生成 HTML,对函数式编程友好
  3. 生态好,应对各种场景的包都有。

怎么实现的虚拟节点?

虚拟节点的本质:虚拟节点的本质就是在 JS 和 DOM 之间做一个缓存,可以类比 CPU 和硬盘,既然硬盘这么慢,我们就也在他们之间添加一个缓存; 既然 DOM 这么慢,我们就可以在 JS 和 DOM 之间添加一个缓存。 CPU(JS)只操作内存(虚拟 DOM),最后的时候在把变更写入硬盘(DOM)。

diff 算法:

  1. 用 Js 对象来表示 DOM 树的结构,需要记录他的节点类型(tagName)、属性(props)、子节点(children); 然后用这个树构建一个真正的 DOM 树,插入到文档中。
  2. 当状态变更的时候,重新构造一个新的对象树,然后用这个新的树和旧的树作对比,记录两个树的差异。
  3. 深度遍历优先,记录差异
  4. 在深度优先遍历的时候,每遍历到一个节点就把该节点和新的树进行对比,如果有差异的话就记录到一个对象里面。差异包括:替换原来的节点; 移动、删除、新增子节点;修改了节点的属性。 ;对于文本节点,文本内容可能会改变。
  5. 把 2 所记录的差异应用在步骤一所构建的真正的 DOM 树上,视图就更新了。

解释一下 304

304 not modified,表示服务器允许访问资源,但因为发生请求未满足条件的情况。用于协商缓存,缓存分为强缓存和协商缓存,协商缓存的机制是如果缓存过期了,就需要发起请求验证资源是否有更新。当浏览器发起请求验证资源时,如果资源没有做改变,那么服务端就会返回 304 状态,并且更新服务器缓存有效期。

如何判断服务器资源是否更新

last-modified:last-modified 和 if-modified-since 是成对出现的

  • last-modified 在响应头里,服务器告诉浏览器,这个资源的最后修改时间是什么
  • if-modified-since 在请求头里,告诉服务器我所请求的这个资源最后修改时间是什么。服务器根据这个值来判断,如果这个值和服务端这个资源现有的值一致,直接返回 304 和空的 body,如果和服务端现有的值不一致(资源已经更新),则返回 200 和最新资源。
    etag:etag 和 if-none-match 是成对出现的
  • etag 是服务器根据一定规则生成的资源‘指纹’,传递给客户端,客户端将其与缓存一起保存
  • if-none-match 是客户端在向服务端请求指定资源时,将本地的 etag 值通过信息头传递给服务端,服务端与其当前版本的资源的 ETag 进行比较,如果两个值匹配(即资源未更改),服务器将返回不带任何内容的 304 未修改状态,告诉客户端缓存版本可用。如果 etag 值匹配不成功,返回 200 code 和资源内容。

对 http 了解多少?http header 中都有哪些东西?

HTTP 协议最大的特点是「无状态」。客户端向服务器端发起一个请求。然后服务器端返回一个响应。HTTP 协议传输的内容是 HTTP message。
报文分成两种,一种是 Request 请求,通常用于浏览器告诉服务器它想要什么;一种是 Response 响应,通常用于服务器给浏览器返回它要的内容。
报文的基本格式:开始行,消息头,空行,消息体。
Request:请求行,请求头,空行,消息体(可空)

  • 请求行:请求方法 URI 协议版本号 。
  • 请求头:Referrer 请求发起页面的地址 User-Agent 客户端信息 Host 主机域名 Max-forwards 请求最大转发次数
    Response:状态行,响应头,空行,消息体。
  • 状态行:协议版本号 状态码
  • 响应头:ETage:Entity 的唯一编码,修改后更新;Retry-after:N 秒后重试;Location:转向到 Server Web Server 相关信息
    消息体:可空。
    实体头字段:Allow:支持的 HTTP 方法;Expires:过期时间; Content-Encoding:编码格式;Content-Language:编码格式; Content-Length:内容长度(字节);Content-Type:媒体类型。

页面出现空白,怎么排查定位问题?

  1. 先确保网络连接通畅。
  2. 查看网络 url 地址是否输入有误。
  3. 打开控制台查看报错信息。
  4. 查看接口访问是否有请求。
  5. 查看路由是否有 path 或者 name 的错误,导致加载了不存在的页面。

一个父元素 div 里面有 n 个 a 标签,对 a 有一些事件需要处理,怎么处理?

使用事件代理,绑定在父元素上,看事件的出发点是不是 a 标签。代码如下:

1
2
3
4
5
6
7
8
$("#div").addEventListener("click", function (e) {
// e.target 可以监听到触发点击事件的元素是哪一个
var target = e.target;
if (e.nodeName === "A") {
// 点击的是 <a> 元素
// 进行要处理的内容
}
});

利用了什么性质?

事件冒泡。dom 标准事件流的触发的先后顺序为:先捕获再冒泡
事件捕获:通俗的理解就是,当鼠标点击或者触发 dom 事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。
事件冒泡:与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。使用 stopPropagation()阻止事件冒泡.使用 preventDefault()阻止默认行为

垂直水平居中怎么做?

  1. 利用 css3 的 translate 属性,设置子元素为绝对定位,top,left 为 50%,translate(-50%。-50%)
  2. 利用 flex 布局,对父元素使用,align-items:center 让其在侧轴垂直,就是说垂直居中,如果要水平居中的话,可以使用 justify-centent:center

对于性能优化你有什么看法

参看一面

为什么说 dom 操作耗时?

因为 DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当通过 JS 操作 DOM 的时候,这个操作涉及到了两个线程之间的通信,然后会带来一些性能上的损耗。操作 DOM 次数一多,也就等同于一直在进行线程之间的通信。操作 DOM 可能还会带来重绘回流的情况,所以也就导致了性能上的问题。

什么是重绘?什么是回流?

重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘
回流是布局或者几何属性需要改变就称为回流。
回流一定会触发重绘,而重绘不一定会回流
原因:

  • 添加或删除可见的 DOM 元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
  • 页面一开始渲染的时候(这肯定避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

如何避免:

  • 使用 transform 替代 top,left,right,bottom
  • 使用 visibility 替换 display:none,前者只会重绘,后者会引发回流
  • 不把界面的属性值放在一个循环里当循环的变量
  • 不用 table 布局