一名深漂程序员:我所整理和收集的前端面试题
Posted 我是真的不会前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一名深漂程序员:我所整理和收集的前端面试题相关的知识,希望对你有一定的参考价值。
1.重绘和回流
什么是重绘?什么是回流?
在页面加载时,浏览器把获取到的html代码解析成1个DOM树,DOM树里包含了所有HTML标签,包括display:none隐藏,还有用JS动态添加的元素等。
浏览器的解析过程
- html结构 解析html结构 生成dom树(doucment object model)
- css样式 解析css样式 生成cssom树
- dom+cssom 渲染 Render Tree
回流:根据生成的渲染树,获取浏览器中节点信息(标签名称、属性)
重绘:根据渲染树和回流节点信息,获取到具体的节点样式信息(属性值)
两者之间的关系:
- 有回流必有重绘 color:red => background:
- 有重绘不一样有回流 color:red => color:green
哪些情况会造成回流重绘
- 元素位置改变
- 浏览器的可视窗口变换
- 删除和添加dom!!!
2.事件循环机制
这是某同学在面一个大厂前端时二面还是第几面不记得了问到的
JS的代码执行是基于一种事件循环的机制,之所以称作事件循环
MDN给出的解释为因为它经常被用于类似如下的方式来实现
如果当前没有任何消息queue.waitForMessage 会等待同步消息到达
我们可以把它当成一种程序结构的模型,处理的方案。更详细的描述可以查看 这篇文章
而JS的运行环境主要有两个:浏览器、Node。
在两个环境下的Event Loop实现是不一样的,在浏览器中基于 规范 来实现,不同浏览器可能有小小区别。在Node中基于 libuv 这个库来实现
JS是单线程执行的,而基于事件循环模型,形成了基本没有阻塞(除了alert或同步XHR等操作)的状态
Macrotask 和 Microtask
在js中每个线程都有一个事件循环(Event Loop),在浏览器中除了主要的页面执行线程 外,Web worker是在一个新的线程中运行的,所以可以将其独立看待。
在事件循环中。有至少一个任务队列(Task Queue,也可以称作Macrotask宏任务),各个任务队列中放置着不同来源(或者不同分类)的任务,可以让浏览器根据自己的实现来进行优先级排序
以及一个微任务队列(Microtask Queue),主要用于处理一些状态的改变,UI渲染工作之前的一些必要操作(可以防止多次无意义的UI渲染)
主线程的代码执行时,会将执行程序置入执行栈(Stack)中,执行完毕后出栈,另外有个堆空间(Heap),主要用于存储对象及一些非结构化的数据
宏任务与微任务队列里的任务随着:任务进栈、出栈、任务出队、进队之间交替着进行
当我们从macrotask队列中取一个任务处理,处理完成之后,从microtask队列中一个个按顺序取出所有任务进行处理,处理完成之后进入浏览器渲染后续工作
需要注意的是:microtask并不是在macrotask完成之后才会触发,在回调函数之后,只要执行栈是空的,就会执行microtask。也就是说,macrotask执行期间,执行栈可能是空的(比如在冒泡事件的处理时).然后循环继续。
常见的macrotask有:
常见的macrotask包括:
run <script>(同步的代码执行)
- setTimeout
- setInterval
- setImmediate (Node环境中)
- requestAnimationFrame
- I/O
- UI rendering
常见的microtask包括:
- process.nextTick (Node环境中)
- Promise callback
- MutationObserver
3.js垃圾处理机制
这是我认识的一个面试官问的一个科班出身的前端的第一个问题:
JS 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
javascript垃圾回收的机制其实不复杂:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束,而闭包中由于内部函数的原因,外部函数并不能算是结束。
标记清除
在 JS 中,最常用的垃圾收集方法就是标记清除。当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为进入。从逻辑上讲,永远不能释放那些进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能用到他们。而当变量离开环境时,则将其标记为离开。垃圾收集器在运行的时候会给存储在内存中的变量都加上这样的标记,然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。绝大多数的浏览器都是通过标记清除的方法来管理内存的。
引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。
不是很常用。
function test(){
var a = {} ; //a的引用次数为0
var b = a ; //a的引用次数加1,为1
var c =a; //a的引用次数再加1,为2
var b ={}; //a的引用次数减1,为1
}
4.页面布局中,文本输入框和按钮对不齐的问题
原因:当type类型为button的时候,盒子是怪异盒模型(边框向内长的)
解决方案很多种:解决方法:给两个同时加上vertical-align:top;
2.ie兼容问题:解决-将input的父级元素的position属性强行设置为relative,然后将input的position属性设置为absolute,并将input的top值设置为0,
5.如何保存token-localStorage存储
通过vue-router的beforeEach钩子,在每次路由到一个地址的时候先判断该路由是否携带了meta信息,且该信息中的requireAuth是否为true,如果为true表示该路由是需要身份验证的。则去localStorage找token,若token不存在则表示用户无认证,去登录请求token。若token存在则拿着token去请求。
以上是关于一名深漂程序员:我所整理和收集的前端面试题的主要内容,如果未能解决你的问题,请参考以下文章