2018腾讯春招实习生面试
时间:2018-3-14
bg:sng-qq空间前端
项目和框架
- 是否阅读过源码:对angular1的digest循环进行解释
- 框架的理解,为何选择这类框架,底层实现的机制,mvvm的理解
- 虚拟dom,设计虚拟dom的diff算法
- 比较两棵dom树
深度优先遍历,定义差异的类型(修改节点属性,修改节点文本内容,替换原有的节点,节点位置变化包括移动删除 - 记录差异
深度遍历过程当中根据定义的修改操作,push进一个队列当中进行最小化修改
- 比较两棵dom树
缓存
- 强缓存和协商缓存的过程
- 使用local storage储存用户输入的密码会有什么风险
xss漏洞的攻击 - Local storage储存首屏加载的css带来的问题
前端首页加载的性能优化,如何更新css的问题 - localstorage会引起xss漏洞的原因,怎么解决
- 使用
local storage
控制文件缓存- 使用loader加载静态文件
对所有动态发起的请求进行拦截,查看请求的的文件url是否缓存到localstorage当中,并判断是否过期 - 借助服务器将静态文件inline
在第一次响应的时候把文件都内联进html中,只要文件版本没有变化(存到cookie)localstorage当中村了读取该文件的代码,通过id查找,或有xss风险
- 使用loader加载静态文件
性能
- 回流和重绘的理解
- 静态资源放在缓存当中如何接收更新:只回答了html5.manifest的内容(没有深入,大概是这个方向)
- 如何提高前端的性能:
- 减少dom操作(问到了“获取dom的代码会有性能损耗吗”)
- 减少http请求
- 使用打包工具,jscss混淆压缩
- 图片压缩
- Cdn内容分发
- 使用缓存
- 服务端方面提到了代理服务器和负载均衡机制
js
- 使用async\await解决了什么问题
- 使用promise带来的问题
- promise的参数
- 使用Array(100).fill(1).map(function(x, index) {return index + 1}) 生成一个1-100的数组并每隔一秒输出
- 对闭包的理解
- 对原型链的理解
- 用什么脚本判断是处于node环境还是浏览器环境
其他相关知识
- Tcp/ip有哪层http、dns、tcp在哪一层
- Mysql varchar和char的区别(只回答了长度区别,应该答一个可变,一个不可变)
- 快排的过程,时间复杂度(nlogn, n^2),空间复杂度(logn,n)
- 数组和链表的区别
个人感受
面试流程的进度还是相当快的,投简历之后就是一面二面连续,其中二面的面试时间最长,也觉得收获比较大,提问的模式是树形的不断往深挖,面试官应该想考察对某些知识能够达到的深度,最好是能够有自己的思考,最好有一些亮点能够吸引面试官。可能是因为线上电话面试的原因,代码层面没有怎么考察,这部分是我比较薄弱的,因为我没有足够多的时间去刷题,对原生js仍旧不太熟悉。所幸面试官想考察的重点不是这里,应该是其他方面的基础,所以计算机相关的重要科目都应该大体的复习一遍。另外,项目经历当中,其实面试官并不是很感兴趣,主要是项目的深度和广度不够,要把握好自己项目当中的亮点,介绍给面试官。
知识点
浏览器的回流与重绘
回流必将引起重绘,重绘不一定引起回流
导致回流的操作
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的DOM元素
- 激活CSS伪类(例如::hover)
- 查询某些属性或调用某些方法
导致回流的属性和方法
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- getBoundingClientRect()
- scrollTo()
重绘
当页面的元素样式的改变不影响它在文档流当中的位置时,浏览器将新样式赋予元素并重新绘制
解决方法
浏览器会维护一个重绘呵回流操作的队列,当访问上述属性和方法的时候,则清空队列,执行操作
css
- 避免使用table布局。
- 尽可能在DOM树的最末端改变class。
- 避免设置多层内联样式。
- 将动画效果应用到position属性为absolute或fixed的元素上。
- 避免使用CSS表达式(例如:calc())。
javascript
- 避免频繁操作DOM和样式
- 先将元素设置为
display: none
,在该元素上进行DOM操作则不会引发回流和重绘 - 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
js继承
js继承不同于其他面向对象语法通过类进行继承,而是通过constructor
,利用prototype
去构造原型链当中的属性实现继承
_proto_
属性,指的是被继承对象的prototype
1 | var horse = new Horse(); |
constructor
的prototype
指向的就是原函数- 当调用
new
,将该函数当作构造器的时候,js会生成constructor
实例
1 | foo._proto_ === Foo.prototype; |
ts当中的继承
使用了一个立即执行函数,并返回constructor
构造函数,类当中的方法就在原型链当中进行设置
1 | let Greeter = (function() { |
promise shortcomings
- 无法中断与重试。
- resolve只会执行一次。
- promise立即执行。
TCP三次握手四次挥手
使用原生js实现Ajax请求
- 创建
1 | var xhr = new XMLHttpRequest(); |
- 连接与发送
需要区分方法和相应的参数,open函数的三个参数:请求方式、请求地址、是否为异步请求
1 | if (options.type == "GET") { |
- 接受
监听
onreadystatechange
事件,判断readyState
的值,再读取status
状态码确定状态,并调用相应的回调函数,传入响应体xhr.responseText
进行处理
1 | xhr.onreadystatechange = function () { |
http请求
- 请求消息
- 请求行:请求方法、URL、协议版本
- 请求头
- 空行
- 请求数据
- 响应消息
- 状态行:协议、状态码、状态码含义
- 消息报头
- 空行
- 响应正文
http2.0
- 多路复用:同一个TCP连接可以并发处理多个HTTP请求,并发请求的数量级也增大
- 建立长连接需要指定keep-alive字段(1.0和1.1的主要区别)
安全防范
XSS
- 通过字符转义进行代码解析
- 浏览器端增加
HttpOnly
字段,防止cookie
被XSS漏洞读取,(但是XSS漏洞可以读取localstorage
)
CSRF
- 提交的时候增加验证码(降低用户体验)
- 根据当前的session和用户id创建
token
,然后本页面当中所有post请求都应该携带这个token
网站劫持
在数据传输的过程当中在缓存服务器或者其他中间服务器信息遭到泄漏,应该加密传输
CORS跨域资源共享
危害CSRF跨站请求伪造
图中A和B就是不同域的资源。
CORS验证机制
出于安全原因,浏览器限制从脚本中发起的跨域HTTP请求。默认的安全限制为同源策略, 即JavaScript或Cookie只能访问同域下的内容。
客户端处理机制
简单请求
请求方法为
GET
,HEAD
,POST
,请求头是下列之一application/x-www-form-urlencoded
,multipart/form-data
,text/plain
HTTP请求头当中会携带Origin
,响应的头部信息当中会有Access-Control-Allow-Origin
,Access-Control-Allow-Methods
返回验证结果,如果服务端不允许跨域访问,会返回403,并且在控制台报错
预先请求
当请求不是简单请求的时候,浏览器会发送
OPTION
请求,请求的头部信息会包含Origin
、Access-Control-Request-Method
、Access-Control-Request-Headers
,根据响应头当中Access-Control-Allow-Origin
,Access-Control-Allow-Methods
,Access-Control-Allow-Headers
判断是否发送这个请求,否则返回403,浏览器不会发送跨域请求,并且控制台报错
带认证的请求
当需要把
cookie
跨域发送的时候需要- XHR
withCredentials = true
- 服务器响应
Access-Control-Allow-Credentials: true
这个头部信息 - 响应头部
Access-Control-Allow-Origin
应该是一个具体的域名,而不是通配符
- XHR
服务端处理机制
- 检查是否有
ORIGIN
字段 - 判断
method
是否是OPTION
- 如果是简单请求,返回
Access-Control-Allow-Origin
,Access-Control-Allow-Methods
和正常内容 - 如果是预先请求,返回
Access-Control-Allow-Headers
,Access-Control-Allow-Methods
,Access-Control-Allow-Origin
,内容为空
- 如果是简单请求,返回
头部信息
Access-Control-Max-Age
: 预先请求检查请求返回结果缓存的时间,浏览器使用该结果判断是否发送跨域请求
浏览器的多进程与javascript的单线程
- 浏览器当中每开一个tab则创建一个新的进程
- brower进程:浏览器的主进程(负责协调、主控),与用户交互,管理页面,绘制render进程写到的内存中的bitmap
- GPU进程:用于3d绘制
- render进程:进行页面渲染,脚本执行和事件处理(浏览器内核层面)
- GUI渲染线程
- js引擎线程
- 事件触发线程
- 定时触发器线程
- 异步http请求线程
其中js引擎线程和GUI渲染线程是互斥的,GUI的更新会保存在一个队列当中等js引擎空闲的时候执行
浏览器渲染
- 将元素变成复合图层,硬件加速,脱离普通文档流,不会影响默认复合层的的回流和重绘
- translate3d、translateZ、opacity,动画执行的过程会创建合成层
- absolute会脱离普通文档流,但不会脱离默认复合层,元素的改变还是会引起复合层的重绘
定时器线程
js引擎线程的事件循环(需要等执行栈的代码执行完,才会读取事件队列当中的事件,执行回调),js引擎线程会发生阻塞,因此需要另外的线程进行定时,完成后将事件推到事件队列当中等待执行,所以还是会存在误差
- macrotask(宏任务):主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)
- microtask(微任务):Promise,process.nextTick等(在node环境中,promise优先级比较低)
异步过程的通信机制
异步过程会启动工作进程执行异步任务,将消息放到消息队列,主线程通过事件循环过程去取消息,当消息队列为空的时候主线程阻塞