近日被各种大中小厂问到的,我和其他两个同事的面题汇总,无非就是些基础的题目以及深入追问。小弟不才,贴上问题的同时也加入了自己的口头总结,大神可以忽略或者自行搜索答案。
- url到渲染页面过程 导航->响应->解析->渲染->交互。 DNS查找,返回ip地址,TCP三次握手,有https还得进行TLS协商经过8次往返。TCP慢开始,第一个包14kb大小,之后翻倍。通过发送包和客户端返回的确认帧来阻塞控制确定发送速率。之后便是解析,
- 处理html标记并构造DOM树,没有async或者defer的script会阻塞渲染并停止html的解析,预加载扫描器会在后台检索资源减少阻塞。
- 处理css并构建cssom树,速度非常快。
- 将dom和cssom组合成render树,head和它子节点还有display:none将不会显示。
- 在渲染树上运行布局以计算每个节点的几何体,第一次确定节点大小和位置叫做布局,随后对大小和位置的重新计算叫做回流。
- 最后将各个节点绘制在屏幕上,必须在16.67毫秒内完成,将内容提升到GPU层可以提高绘制和重绘性能,只是加大内存管理。dom加载过程花费的时间不等,一般我们项目在1秒到3秒,此时屏幕事件没有响应。
2 数组和链表的区别,找数组快还是链表快 区别:
- 数组是顺序的储存结构,链表是链式的储存结构
- 数组将所有元素按次序依次储存,链表通过指针来连接元素与元素
- 数组便于查找和修改,不方便新增和删除。链表反之。 数组快,原因:
- 数组内存连续,数据类型相同,所以可以直接下标定位到元素,链表则要遍历。
- 内存连续可以直接用公式定位到地址,而链表则需要next指针来一次指向。
- 连续内存可以使用CPU缓存,而链表的节点分布在堆内存上,只能读取内存,所以时间要慢
- 说说三次握手,为什么要三次 保证数据可靠传输,又要提高传输的效率。
- TCP 需要 seq 序列号来做可靠重传或接收,而避免连接复用时无法分辨出 seq 是延迟或者是旧链接的 seq,因此需要三次握手来约定确定双方的 ISN(初始 seq 序列号)
- 防止已失效的连接请求又传送到服务器端,因而产生错误。三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
- TCP 传递信息可以理解为美国与中国用货船来传货物,但因为一首轮船穿放不下,货物要分开一只只轮船来发货。所以需要一个序列号来识别该货物是第几个,以便到达后将其拼接回原来的货物。因为同一条航道(也就是 tcp连接)上,可能会有多批货物发送(复用 tcp 连接)。发货时,双方需要通知对方这个序列号是从哪里开始(init seq)的,这样才能辨识过来的是不是一个对的货物,以及能拼接成完整的货物。货物运输拼接(tcp)最重要的是可靠性,如果没有用三次握手来确认双方都可以获得对方的 序列号(seq)的话,就无法知道当前航班(连接)中,对的货物序号是怎么样的了。
4. https是怎么加密的
- 对称加密。两人有相同的密钥(只有两人知道),弊端:密钥无法安全传输,要线下交换密钥,如果通信比较多就很麻烦
- 非对称加密RSA。A先用B公开的公钥加密,然后发送给B,B收到后用自己的私钥去解密。弊端:比堆成加密慢百倍。
- 结合。先生成对称加密算法的密钥,然后用非对称加密(RSA)的方式安全地发送给对方。随后就不用RSA,用对称加密的算法了。
- 更安全就需要认证中心(CA)和数字证书。CA有上级认证,链式的,非常安全
- 说说重排与重绘 浏览器渲染页面默认采用的是流式布局模型(Flow Based Layout)
4、生成布局(flow),即将所有渲染树的所有节点进行平面合成。重排(回流) 5、将布局绘制(paint)在屏幕上。重绘
-
第四步和第五步是最耗时的部分,这两步合起来,就是我们通常所说的渲染。网页生成的时候,至少会渲染一次。在用户访问的过程中,还会不断重新渲染。重新渲染需要重复之前的第四步(重新生成布局)+第五步(重新绘制)或者只有第五个步(重新绘制)。
-
重排是什么:重新生成布局。当DOM 的变化影响了元素的几何属性(宽和高)--比如改变边框宽度或给段落增加文字导致行数增加--浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。
-
重绘是什么:重新绘制。完成重排后,浏览器会重新绘制受影响的部分到屏幕中。这个过程称为重绘。
-
重排一定会导致重绘,重绘不一定导致重排
-
浏览器会尽量把所有的变动集中在一起,排成一个队列,然后一次性执行
-
强制刷新队列的style样式请求:offsetTop, offsetLeft, offsetWidth, offsetHeight,scrollTop, scrollLeft, scrollWidth, scrollHeight,clientTop, clientLeft, clientWidth, clientHeight,getComputedStyle(), 或者 IE的 currentStyle.我们在开发中,应该谨慎的使用这些style请求,注意上下文关系,避免一行代码一个重排,这对性能是个巨大的消耗!!!
-
性能优化:1. 分离读写操作。2. 样式集中改变。3. 缓存布局信息(变量存信息)。4. 离线改变dom(在要操作dom之前,通过display隐藏dom,当操作完成之后,才将元素的display属性为可见,因为不可见的元素不会触发重排和重绘。通过使用DocumentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排)。5. position属性为absolute或fixed(重排开销比较小)。6. 优化动画(可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小)。7.不要使用table布局。8.开启硬件加速。9.替换高性能api。10.减少dom操作
-
发生重排的情况:添加或删除可见的DOM元素。元素位置改变。元素本身的尺寸发生改变。内容改变。页面渲染器初始化。浏览器窗口大小发生改变。
- 宏任务与微任务 js运行机制:
- 概念1: JS是单线程执行,”JS是单线程的”指的是JS 引擎线程。在浏览器环境中,有JS 引擎线程和渲染线程,且两个线程互斥。Node环境中,只有JS 线程。
- 概念2:执行栈。是一个存储函数调用的栈结构,遵循先进后出的原则。后执行的函数会先从栈中弹出。
- 概念3:Event Loop。JS引擎常驻于内存中,等待宿主将JS代码或函数传递给它。也就是等待宿主环境分配宏观任务,反复等待 - 执行即为事件循环。 Event Loop中,每一次循环称为tick,每一次tick的任务如下: 1、执行栈选择最先进入队列的宏任务(一般都是script),执行其同步代码直至结束; 2、检查是否存在微任务,有则会执行至微任务队列为空; 3、如果宿主为浏览器,可能会渲染页面; 4、开始下一轮tick,执行宏任务中的异步代码(setTimeout等回调)。
- ES6 规范中,microtask 称为 jobs,macrotask 称为 task。宏任务是由宿主发起的,而微任务由JavaScript自身发起。
拓展:async和await是如何处理异步任务的?
- usestate原理,为什么要放到最上面
- usestate和之前的setState有啥区别
- 类组件和函数式组件
- 在类组件中定义状态用state定义,但是修改状态必须要用到setState来修改,为了更好的感知性能,React 会延迟调用setState,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效
- 函数式组件里面,由于对 state 的读取没有通过 this. 的方式,使得 每次 setTimeout 都读取了当时渲染闭包环境的数据,虽然最新的值跟着最新的渲染变了,但旧的渲染里,状态依然是旧值。
- react hook callback知道吗 因为没有shouldComponentUpdate,所以使用这三个来优化性能。 这里将 memo, useMemo, useCallback 三个Hook放在一起做个对比归纳如下:
- React.memo 缓存组件,使得组件可以 ”有选择“的更新
- useMemo 缓存某个变量,第二个参数是依赖项。使得函数组件变量变化时候,组件可以”有选择“的去执行某些业务
- useCallBack 缓存某个方法,特别是子组件调父组件的场景,避免子组件重复渲染 老版的解决方案:使用immutable进行比较,在不相等的时候调用setState;在shouldComponentUpdate中判断前后的props和state,如果没有变化,则返回false来阻止更新。 补充:immutable(不可改变的)是一种持久化数据。一旦被创建就不会被修改。修改immutable对象的时候返回新的immutable。但是原数据不会改变。
- 补充:useEffect、useMemo、useCallback都是自带闭包的。也就是说,每一次组件的渲染,其都会捕获当前组件函数上下文中的状态(state, props),所以每一次这三种hooks的执行,反映的也都是当前的状态,你无法使用它们来捕获上一次的状态。对于这种情况,我们应该使用ref来访问。
- ts用到哪种程度
- react从修改state到渲染页面中间过程 首先,需要根据原来的this.state和传进来的参数来判断是否批量更改(是否批量差了一个收集待改组件的步骤),而这里的this.state是默认传进来的.
然后,再根据this.state来计算nextstate. (shouldComponentUpdate()根据拿到的nextstate来返回一个布尔值,true则进行下一步,false,则下一步不执行.然后就进入componentWillUpdate)
接着render()出一个next组件,
最后根据diff算法进行更新渲染. 结束后进入生命周期函数componentDidUpdate()
12. 虚拟dom diff算法,里面是如何对比的
- 虚拟DOM就是一个真实DOM转换的JS对象。
- 1.React通过制定大胆的diff策略,将 O(n3) 复杂度的问题转换成 O(n) 复杂度的问题;React是如何将O(n3) 复杂度的问题转换成 O(n) 的? (1)只进行同级比较 (2)不同类的React组件会被当做完全不同的DOM结构而被完全替换 (3)key prop:开发人员可以通过给Virtual DOM一个唯一的key属性暗示React这是同一个DOM结构,反之若key值不同则会被当做完全不同的DOM结构。
- 2.React通过分层求异的策略,对tree diff进行算法优化;
- 3.React通过相同类生成相似树形结构,不同类生成不同树形结构的策略,对component diff进行算法优化。
- 4.React通过设置唯一key的策略,对element diff进行算法优化;
- 5.建议,在开发组件时,保持稳定的DOM结构会有助于性能的提升;
- 6.建议,在开发过程中,尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,在一定程度上会影响React的渲染性能
- 如何做react的优化
- antd的modal是怎么实现让其在外部展示的
- 父子组件间的通信,父组件如何调用子组件函数、组件间的相互调用方法
- 如何写好一个组件,需要注意什么
- setstate同步还是异步
- react16.3前后的生命周期变化
- 框架和原生渲染方式有何不同
- 虚拟dom的实质和作用
- class组件相比函数式组件有什么可取的地方
- render里面有数字要注意什么
- react元素上面的事件是怎么绑定的,会不会冒泡
- 父子组件...props容易出现什么问题
- 说说es6有哪些属性
- foreach如何跳过一个循环
- for in和for of的用法和区别,in有哪些缺点,of如何改造实现in一样的功能
- 如何查询对象里面的属性是不是在原型上,在使用的时候怎么避免调用出错,如何判断是不是一个纯粹的object对象
- 谈谈promise,以及为什么它可以链式
- async await 如何模拟promise
- promise.all 和promise.rice的区别
- 手写promise以及promise.all
- fetch和原生ajax区别、回调地狱
- 防抖和节流,以及使用场景
- 谈谈this的理解,改变this指向的方法
- px、em、rem的区别
- media媒体查询
- div垂直居中的方法
- 说出三种左边导航固定右边布局自适应的方法
- 说出三种对象以及对象方法
- let、var、const区别,const a=[],可以往a数组里面push东西吗
- js动画和css动画的区别
- css选择器的优先级
- 如何将无序数组按照每一项对象里有序字段排序
- 数组在内存中是先分配内存在生成还是动态生成
- 数组的方法
- 强缓存弱缓存
- 如何解决跨域
- webpack打包
- flex:1代表什么
- 移动端h5和web页面写的时候需要注意什么
- height:100%和height:100vh区别
- 说出10个数组的方法以及它的参数,以及哪些改变原数组哪些不改变
- 处理打包后过大的js文件,做过拆包吗?
- localstorage、seaaionstorage、cookie的区别
- 如何管理git,多人改一个分支冲突了怎么办
- 如何切换项目版本
- 谈谈简历上的项目主要负责模块功能和技术点