前端性能优化面试问题

一、从输入URL到页面加载显示完成都发生了什么?

这个问题的根本:知识点广,区分度高。

回答思路:渲染过程是重点,其他自己擅长的点可以适当展开。

如何解答:

1、UI thread(UI线程)先判断输入的是搜索还是URL地址,如果是搜索则启用浏览器设置的默认搜索引擎进行搜索,如果是URL则开始URL的相应解析请求。

URL的组成结构可以细讲一下,如下图拆解图。

2、UI线程执行完之后会通知Network thread(网络线程),开始发起网络请求。

网络请求步骤:

  (1)、DNS查找IP

  (2)、协议是https,需要建立TLS连接

  (3)、如果收到301状态码,重新执行Network thread(网络线程)发起新请求,跟重定向新地址创建连接

  (4)、设置UA等信息,发送GET请求

  (5)、服务器上的应用处理请求,组织好Response信息返回给浏览器,对服务端熟悉的可以展开

  (6)、浏览器读取Response信息,分析数据类型

  (7)、安全检查

  (8)、通知UI线程数据准备就绪

UI线程和网络线程都是属于Browser Process(浏览器进程)。

3、Renderer process(渲染进程),重点回答

在渲染进程里,我们最主要也最熟悉的线程是Main thread主线程,主要围绕主线程来回答。

Raster Thread绘制线程,Compositor Thread复合线程。

  (1)解析文本构建DOM

  (2)边解析DOM边加载子资源,如图片,CSS等资源

  (3)JS阻塞解析,如果JS不对DOM做修改的操作,可以使用async/defer属性进行非阻塞加载

  (4)解析CSS,计算computed styles

  (5)构建布局树,位置和大小

  (6)创建绘制记录,确定绘制顺序,绘制前的准备工作

  (7)将页面拆分图层,构建图层树,提高绘制的效率

  (8)复合线程像素画图层,创建一条复合帧,即将所有绘制好的图层合并

以上就是主要以渲染层面回答这个问题的知识点。如果还要继续扩展可以讲http头信息、缓存机制、状态码等。

二、什么是首屏加载?怎么优化?

这个问题的核心:

  (1)Web增量加载的特点决定了首屏性能不会完美

  (2)过长的白屏影响用户体验和留存

  (3)首屏(above the fold)=> 初次印象

如何回答首屏:

首屏的对于用户3个关键时刻:

  (1)白屏时页面发生了什么事情,什么时候可以出现内容,First Contentful Paint(FCP)

  (2)页面开始出现内容知道网站可访问,开始等待页面具体有意义的内容出现完成,Largest Contentful Paint(LCP)

  (3)内容出现后会想页面能不能用,什么时候可以进行交互,Time to Interactive(TTI)

以上三个关键节点的量化指标:

先回答以上首屏的节点和相应指标,后回答如何进行首屏优化:

1、资源体积太大:资源压缩,传输压缩,代码拆分,Tree shaking,HTTP2,缓存

2、首页内容太多:路由/组件/内容 lazy-loading,预渲染/SSR,Inline CSS

3、加载顺序不合适:prefetch,preload

三、JS是怎样管理内存?什么情况会造成内存泄漏?

问题核心:内存泄漏严重影响性能,高级语言不等于不需要管理内存

如何回答:

1、JS相关的内存机制

——变量创建时自动分配内存,不使用时“自动”释放内存,俗称GC。

——所有的GC都是近似实现,只能通过判断变量是否还能再次访问到。

——局部变量,函数执行完,没有闭包引用,就会被标记回收。

——全局变量,直至浏览器卸载页面时释放。

——GC两种实现方式:

  (1)引用计数,无法解决循环引用的问题

  (2)标记清除,不能被访问到的被标记,然后进行清除,这是目前大多数浏览器的实现方式。

  标记清除也有缺陷,如下代码,b属性永远不会被访问,但是因为a一直被访问所以b不会被清除

const obj = { a:new Array(1000),b:new Array(2000)}

setInterval(()=>console.log(obj.a),1000)

2、如何避免内存泄漏

  (1)避免意外的全局变量产生,如方法里面声明变量不使用var,let,const,造成意外的全局变量产生

  (2)避免反复运行引发大量闭包,如下代码

var store;

function outer(){
    var largeData = new Array(10000000);
    var prevStore = store;
   function inner(){
       if(prevStore) return   largeData 
    }
    return function(){}        
}

setInterval(function(){
    store = outer()
},10)

  (3)避免脱离DOM元素,如下代码

function createElement(){
  const div=document.createElement('div');
  div.id='detached';
  return div
}

const detachedDiv = createElement();

document.body.appendChild(detachedDiv);

function deleteElement(){
  document.body.removeChild(document.getElementById('detached'))
}

deleteElement()

  上述代码虽然detached这个DOM元素以及被删除掉了,但是detachedDiv这个变量引用了这个DOM元素,这个变量没有被回收那么这个DOM元素依然会存在内存中。

放弃安逸,持续努力——成长
原文地址:https://www.cnblogs.com/MarsPGY/p/15807157.html