JS

215 阅读13分钟

近日被各种大中小厂问到的,我和其他两个同事的面题汇总,无非就是些基础的题目以及深入追问。小弟不才,贴上问题的同时也加入了自己的口头总结,大神可以忽略或者自行搜索答案。

  1. url到渲染页面过程 导航->响应->解析->渲染->交互。 DNS查找,返回ip地址,TCP三次握手,有https还得进行TLS协商经过8次往返。TCP慢开始,第一个包14kb大小,之后翻倍。通过发送包和客户端返回的确认帧来阻塞控制确定发送速率。之后便是解析,
  1. 处理html标记并构造DOM树,没有async或者defer的script会阻塞渲染并停止html的解析,预加载扫描器会在后台检索资源减少阻塞。
  2. 处理css并构建cssom树,速度非常快。
  3. 将dom和cssom组合成render树,head和它子节点还有display:none将不会显示。
  4. 在渲染树上运行布局以计算每个节点的几何体,第一次确定节点大小和位置叫做布局,随后对大小和位置的重新计算叫做回流。
  5. 最后将各个节点绘制在屏幕上,必须在16.67毫秒内完成,将内容提升到GPU层可以提高绘制和重绘性能,只是加大内存管理。dom加载过程花费的时间不等,一般我们项目在1秒到3秒,此时屏幕事件没有响应。

2 数组和链表的区别,找数组快还是链表快 区别:

  1. 数组是顺序的储存结构,链表是链式的储存结构
  2. 数组将所有元素按次序依次储存,链表通过指针来连接元素与元素
  3. 数组便于查找和修改,不方便新增和删除。链表反之。 数组快,原因:
  4. 数组内存连续,数据类型相同,所以可以直接下标定位到元素,链表则要遍历。
  5. 内存连续可以直接用公式定位到地址,而链表则需要next指针来一次指向。
  6. 连续内存可以使用CPU缓存,而链表的节点分布在堆内存上,只能读取内存,所以时间要慢
  1. 说说三次握手,为什么要三次 保证数据可靠传输,又要提高传输的效率。
  • TCP 需要 seq 序列号来做可靠重传或接收,而避免连接复用时无法分辨出 seq 是延迟或者是旧链接的 seq,因此需要三次握手来约定确定双方的 ISN(初始 seq 序列号)
  • 防止已失效的连接请求又传送到服务器端,因而产生错误。三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
  • TCP 传递信息可以理解为美国与中国用货船来传货物,但因为一首轮船穿放不下,货物要分开一只只轮船来发货。所以需要一个序列号来识别该货物是第几个,以便到达后将其拼接回原来的货物。因为同一条航道(也就是 tcp连接)上,可能会有多批货物发送(复用 tcp 连接)。发货时,双方需要通知对方这个序列号是从哪里开始(init seq)的,这样才能辨识过来的是不是一个对的货物,以及能拼接成完整的货物。货物运输拼接(tcp)最重要的是可靠性,如果没有用三次握手来确认双方都可以获得对方的 序列号(seq)的话,就无法知道当前航班(连接)中,对的货物序号是怎么样的了。

WechatIMG312.png

4. https是怎么加密的

  • 对称加密。两人有相同的密钥(只有两人知道),弊端:密钥无法安全传输,要线下交换密钥,如果通信比较多就很麻烦
  • 非对称加密RSA。A先用B公开的公钥加密,然后发送给B,B收到后用自己的私钥去解密。弊端:比堆成加密慢百倍。
  • 结合。先生成对称加密算法的密钥,然后用非对称加密(RSA)的方式安全地发送给对方。随后就不用RSA,用对称加密的算法了。
  • 更安全就需要认证中心(CA)和数字证书。CA有上级认证,链式的,非常安全
  1. 说说重排与重绘 浏览器渲染页面默认采用的是流式布局模型(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元素。元素位置改变。元素本身的尺寸发生改变。内容改变。页面渲染器初始化。浏览器窗口大小发生改变。

  1. 宏任务与微任务 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自身发起。

WechatIMG313.png

拓展:async和await是如何处理异步任务的?

WechatIMG314.png

  1. usestate原理,为什么要放到最上面
  2. usestate和之前的setState有啥区别
  • 类组件和函数式组件
  • 在类组件中定义状态用state定义,但是修改状态必须要用到setState来修改,为了更好的感知性能,React 会延迟调用setState,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效
  • 函数式组件里面,由于对 state 的读取没有通过 this. 的方式,使得 每次 setTimeout 都读取了当时渲染闭包环境的数据,虽然最新的值跟着最新的渲染变了,但旧的渲染里,状态依然是旧值。
  1. 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来访问。
  1. ts用到哪种程度
  2. react从修改state到渲染页面中间过程 首先,需要根据原来的this.state和传进来的参数来判断是否批量更改(是否批量差了一个收集待改组件的步骤),而这里的this.state是默认传进来的.

然后,再根据this.state来计算nextstate. (shouldComponentUpdate()根据拿到的nextstate来返回一个布尔值,true则进行下一步,false,则下一步不执行.然后就进入componentWillUpdate)

接着render()出一个next组件,

最后根据diff算法进行更新渲染. 结束后进入生命周期函数componentDidUpdate()

WechatIMG315.png

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的渲染性能
  1. 如何做react的优化
  2. antd的modal是怎么实现让其在外部展示的
  3. 父子组件间的通信,父组件如何调用子组件函数、组件间的相互调用方法
  4. 如何写好一个组件,需要注意什么
  5. setstate同步还是异步
  6. react16.3前后的生命周期变化
  7. 框架和原生渲染方式有何不同
  8. 虚拟dom的实质和作用
  9. class组件相比函数式组件有什么可取的地方
  10. render里面有数字要注意什么
  11. react元素上面的事件是怎么绑定的,会不会冒泡
  12. 父子组件...props容易出现什么问题
  13. 说说es6有哪些属性
  14. foreach如何跳过一个循环
  15. for in和for of的用法和区别,in有哪些缺点,of如何改造实现in一样的功能
  16. 如何查询对象里面的属性是不是在原型上,在使用的时候怎么避免调用出错,如何判断是不是一个纯粹的object对象
  17. 谈谈promise,以及为什么它可以链式
  18. async await 如何模拟promise
  19. promise.all 和promise.rice的区别
  20. 手写promise以及promise.all
  21. fetch和原生ajax区别、回调地狱
  22. 防抖和节流,以及使用场景
  23. 谈谈this的理解,改变this指向的方法
  24. px、em、rem的区别
  25. media媒体查询
  26. div垂直居中的方法
  27. 说出三种左边导航固定右边布局自适应的方法
  28. 说出三种对象以及对象方法
  29. let、var、const区别,const a=[],可以往a数组里面push东西吗
  30. js动画和css动画的区别
  31. css选择器的优先级
  32. 如何将无序数组按照每一项对象里有序字段排序
  33. 数组在内存中是先分配内存在生成还是动态生成
  34. 数组的方法
  35. 强缓存弱缓存
  36. 如何解决跨域
  37. webpack打包
  38. flex:1代表什么
  39. 移动端h5和web页面写的时候需要注意什么
  40. height:100%和height:100vh区别
  41. 说出10个数组的方法以及它的参数,以及哪些改变原数组哪些不改变
  42. 处理打包后过大的js文件,做过拆包吗?
  43. localstorage、seaaionstorage、cookie的区别
  44. 如何管理git,多人改一个分支冲突了怎么办
  45. 如何切换项目版本
  46. 谈谈简历上的项目主要负责模块功能和技术点