美文网首页前端框架前端
前端面试常见问题——Web篇

前端面试常见问题——Web篇

作者: Marvel_Dreamer | 来源:发表于2020-10-06 20:16 被阅读0次

    1. web安全及防护

    • XSS(cross-site scripting)跨站脚本攻击
      • 原理:恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的
      • 分类
        • 反射型XSS:攻击者通过特定的方式来诱惑受害者去访问一个包含恶意代码的URL。当受害者点击恶意链接URL的时候,恶意代码会直接在受害者的主机上的浏览器执行。例如攻击者在URL后面的参数中加入恶意攻击代码。当用户打开带有恶意代码的URL的时候,网站服务端将恶意代码从URL中取出,拼接在html中并且返回给浏览器端。 用户浏览器接收到响应后执行解析,其中的恶意代码也会被执行到
        • 存储型XSS:将恶意代码上传或存储到服务器中,下次只要受害者浏览包含此恶意代码的页面就会执行恶意代码。例如发表文章,评论等,攻击者将恶意代码提交到目标网站数据库中。用户打开目标网站时,网站服务器将恶意代码从数据库中取出,然后拼接到html中返回给浏览器中。用户浏览器接收到响应后解析执行,那么其中的恶意代码也会被执行。
        • DOM型XSS:客户端的js可以对页面dom节点进行动态的操作,比如插入、修改页面的内容。如果用户在客户端输入的数据包含了恶意的js脚本,但又没有做任何过滤处理的话,应用程序就有可能受到DOM-based XSS的攻击。DOM XSS 是基于文档对象模型的XSS。一般有如下DOM操作:1. 使用document.write直接输出数据。2. 使用innerHTML直接输出数据。3. 使用location、location.href、location.replace、iframe.src、document.referer、window.name等
      • 防范
        • 最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
        • 对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法(CSP)
    • CSRF(Cross-site request forgery)跨站请求伪造
      • 一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法,利用用户的登录态发起恶意请求
      • 原理:攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。如果用户是在登录状态下的话,后端就以为是用户在操作,从而进行相应的逻辑。
      • 防范
        • Get 请求不对数据进行修改
        • 不让第三方网站访问到用户 Cookie 设置HttpOnly属性
        • 阻止第三方网站请求接口
        • 请求时附带验证信息,比如验证码或者 Token
    • XSS与CSRF区别吗
      • XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。
      • CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包
      • 要完成一次CSRF攻击,受害者必须依次完成两个步骤
        • 登录受信任网站A,并在本地生成Cookie
        • 在不登出A的情况下,访问危险网站B
    • sql注入
      • 原理:通过操作输入来修改SQL语句,用以达到执行代码对WEB服务器进行攻击的方法。简单的说就是在web表单、输入域名或页面请求的查询字符串中插入SQL命令,最终使web服务器执行恶意命令的过程
      • 防范
        • 对用户的输入进行校验,可以通过正则表达式,或限制长度,或对用户输入进行转义
        • 不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取
        • 不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接
        • 不要把机密信息明文存放,加密或者hash掉密码和敏感的信息
    • 点击劫持
      • 原理:点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击
      • 防范
        • X-FRAME-OPTIONS 是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用iframe 嵌套的点击劫持攻击。有三个值可选
          • DENY表示页面不允许通过iframe的方式展示
          • SAMEORIGIN表示页面可以在相同域名下通过iframe的方式展示
          • ALLOW-FROM表示页面可以在指定来源的iframe中展示
        • 对于某些远古浏览器来说,并不能支持上面的这种方式,通过 JS 的方式来防御点击劫持了。当通过 iframe 的方式加载页面时,攻击者的网页直接不显示所有内容了

    2. 网站性能优化

    • content方面
      • 减少HTTP请求:合并文件、CSS精灵、base64
      • 减少DNS查询:DNS缓存、将资源分布到恰当数量的主机名
      • 减少DOM元素数量
    • Server方面
      • 使用CDN
      • 配置ETag
      • 对组件使用Gzip压缩
    • Cookie方面
      • 减小cookie大小
    • CSS方面
      • 将样式表放到页面顶部
      • 不使用CSS表达式
      • 使用<link>不使用@import
    • Javascript
      • 将脚本放到页面底部
      • javascriptcss从外部引入
      • 压缩javascriptcss
      • 删除不需要的脚本
      • 减少DOM访问

    3. 首屏优化

    • 为什么会首屏白屏
      • 等待文件加载、渲染树构建、JS 解析等过程,而这些过程比较耗时,导致用户会长时间出于不可交互的首屏灰白屏状态
    • 优化思路
      • 首屏最小化:首屏HTML尽量小,控制DOM节点数、请求数、外链数
      • 懒加载,可视区域尽快显示
      • 将首屏的关键CSS内联至首屏文件
      • 首屏按需加载:隐藏tab页,采用异步加载的方式,只有当用户要看这块内容的时候才去拉取。
      • 合并、压缩素材:CSS文件、CSS雪碧图、压缩
      • 相对固定的小的图片资源使用base64,减少请求
      • 开启HTTP2.0,多路复用、header压缩等
      • CDN加速
      • 缓存service worker、HTML5离线储存manifest
      • SSR服务器渲染

    4. 优化大量图片加载

    • 图片懒加载。
    • 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
    • 如果图片为css图片,可以使用CSSspriteIconfontBase64等技术。
    • 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
    • 如果图片展示区域小于图片的真实大小,则应在服务器端根据业务需要先行进行图片压缩,图片压缩后大小与展示一致。

    5. 过万条数据渲染(requestAnimationFrame)

    • 如何在不卡住页面的情况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就可以通过requestAnimationFrame来每 16 ms 刷新一次
    <script>
      // 插入十万条数据
      const total = 100000;
      // 一次插入20条
      const once = 20;
      // 渲染数据总共需要几次
      const loopcount= total / once;
      let countOfRender = 0;
      let ul = document.queryselector("ul");
      function add() {
        // 优化性能,把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成
        const fragment = document.createDocumentFragment();
        for (let i = 0; i < once; i++) {
          const li = document.createElement("li");
          li.innerText = Math.floor(Math.random()* total);
          fragment.appendChild(li);
        }
        ul.appendchild(fragment);
        countOfRender ++;
        loop();
      }
      function loop() {
        if (countOfRender < loopcount) {
          window.requestAnimationFrame(add);
        }
      }
      loop();
    </script>
    
    • requestAnimationFrame:html5 还提供一个专门用于请求动画的API
      • 由系统决定回调函数的执行时机。60Hz的刷新频率,则每次刷新的间隔中会执行一次回调函数,不会引起丢帧和卡顿
      • 当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停, requestAnimationFrame也会停止渲染,当页面被激活时,动画从上次停留的地方继续执行,节省CPU开销,而setTimeout会在后台一直执行
      • 在高频率事件(resize,scroll等)中,为防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销
    • setTimeout:容易出现卡顿、抖动的现象;原因是: settimeout任务被放入异步队列,只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚; settimeout的固定时间间隔不一定与屏幕刷新时间相同,会引起丢帧。

    6. 移动端Web页面适配

    • 静态布局
      • 通过<meta>标签中的应用设备标识识别移动设备
      • <meta>标签中的viewport标签中设置width,通过js动态修改标签的initial-scale使得页面等比缩放,刚好占满整个屏幕。
      • 优点:最简单,且没有兼容性问题。
      • 缺点:不能根据用户的屏幕尺寸做出不同的表现。
    • 流式布局
      • 页面元素的宽度按照屏幕分辨率进行适配调整,但整体布局不变
      • 布局特点:屏幕分辨率变化时,页面里元素的大小会变化而但布局不变
      • 设计方法:使用百分比定义宽度,高度使用px来固定,可根据可视区域和父元素的实时尺寸进行调整,尽可能的适应各种分辨率。往往配合 max-width/min-width 等属性控制尺寸流动范围以免过大或过小影响阅读。
      • 主要的问题是如果屏幕尺度跨度太大,那么在相对其原始设计而言过小或过大的屏幕上不能正常显示。在大屏手机或横竖屏切换场景下可能会导致页面元素被拉伸变形,字体大小无法随屏幕大小发生变化
      • 设置盒模型的不同属性时,其百分比设置的参考元素不唯一,容易使布局问题变得复杂
    • 弹性布局
      • 使用相对长度单位rem进行布局,达到自适应的目的,rem是相对于根元素font-size计算值的倍数。根据屏幕宽度设置html标签的font-size。
      • 好处是兼容性好,相较于之前的静态布局和百分比方案,页面不会因为伸缩发生变形,自适应效果更佳
      • 缺点是存在小数像素问题,即rem 计算后可能会出现小数像素,浏览器会对这部分小数四舍五入,按照整数渲染,会导致:缩放到低于1px的元素时隐时现,两个同样宽度的元素因为各自周围的元素宽度不同,导致两元素相差1px等问题
    • 响应式布局
      • 通过媒体查询,给不同分辨率的设备编写不同的样式实现响应式布局,用于解决不同设备不同分辨率之间兼容问题
      • 通常是糅合了流式布局+弹性布局,再搭配媒体查询技术使用。
      • 分别为不同的屏幕分辨率定义布局,同时,在每个布局中,应用流式布局的理念,即页面元素宽度随着窗口调整而自动适配。
      • 特点:每个屏幕分辨率下面会有一个布局样式,即元素位置和大小都会变
      • 缺点:(1)媒体查询是有限的,只能适应主流的宽高。(2)要匹配足够多的屏幕大小,工作量不小,设计也需要多个版本。
    • rem和em
      • em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸
      • em转化为像素,大小取决于自身父级元素所设置的px值。父级元素字体大小乘以em值
      • 使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应
      • rem 转化为像素大小取决于页根元素的字体大小,即 html 元素的字体大小。 根元素字体大小乘以 rem 值
    • vw和vh
      • vw(Viewport Width)、vh(Viewport Height)是基于视图窗口的单位,是css3的一部分,基于视图窗口的单位,除了vwvh还有vminvmax
      • vw:1vw`等于视口宽度的1%
      • vh:1vh 等于视口高度的1%
      • vmin: 选取 vw 和 vh 中最小的那个,即在手机竖屏时,1vmin=1vw
      • vmax:选取 vw 和 vh 中最大的那个 ,即在手机竖屏时,1vmax=1vh

    7. 前端监控

    • 为什么需要前端监控
      • 获取用户行为以及跟踪产品在用户端的使用情况,并以监控数据为基础,指明产品优化的方向。
      • 前端监控可以分为三类:数据监控、性能监控和异常监控。
      • 实现前端监控有三个步骤:前端埋点和上报、数据处理和数据分析。
    • 数据监控:监听用户的行为,常见的数据监控包括:
      • 页面浏览量或点击量;访问某个站点或点击某条新闻的不同IP地址的人数
      • 用户在每一个页面的停留时间
      • 用户通过什么入口来访问该网页
      • 用户在相应的页面中触发的行为
    • 性能监控:监听前端的性能,主要包括监听网页或产品在用户端的体验,可根据性能监测的结果进一步优化前端性能,常见的性能监控数据包括:
      • 不同用户,不同机型和不同系统下的首屏加载时间
      • 白屏时间
      • http等请求的响应时间
      • 静态资源整体下载时间
      • 页面渲染时间
      • 页面交互动画完成时间
    • 异常监控:前端代码在执行过程中也会发生异常,因此需要引入异常监控。及时的上报异常情况,可以避免线上故障的发生,常见的需要监控的异常包括:
      • Javascript的异常监控
      • 样式丢失的异常监控
    • 常用前端埋点方案
      • 代码埋点
        以嵌入代码的形式进行埋点,比如需要监控用户的点击事件,会选择在用户点击时,插入一段代码,保存这个监听行为或者直接将监听行为以某一种数据格式直接传递给server端
        优点是可以在任意时刻,精确的发送或保存所需要的数据信息,缺点是工作量较大,每一个组件的埋点都需要添加相应的代码
      • 可视化埋点
        提供一个可视化交互的页面,输入为业务代码,通过这个可视化系统,可以在业务代码中自定义的增加埋点事件等,最后输出的代码耦合了业务代码和埋点代码。实际上跟代码埋点还是区别不大。也就是用一个系统来实现手动插入代码埋点的过程。
        缺点是可视化埋点可以埋点的控件有限,不能手动定制。
      • 无埋点
        不需要工程师在业务代码里面插入侵入式的代码。只需要加载一段定义好的SDK代码,技术门槛更低,使用与部署也简单,避免了需求变更,埋点错误导致的重新埋点。通过SDK代码,前端会自动采集全部事件并上报埋点数据,能够呈现用户行为的每一次点击、每一次跳转、每一次登录等全量、实时用户行为数据。
        优点是不需要关注埋点逻辑,不会出现漏埋、误埋等现象,缺点是自定义属性不灵活,传输时效性差,数据可靠性欠佳,耗费网络流量,还会增加服务器负载
    • 上报周期
      • 如果埋点的事件不是很多,上报可以实时进行
      • 如果埋点的事件较多,或者说网页内部交互频繁,可以通过本地存储的方式先缓存上报信息,然后定期上报
    • 上报方式
      • img标签,不存在跨域问题,兼容性较好
      • ajax
      • navigator.sendBeacon:通过HTTP将少量数据异步传输到Web服务器

    8. 会话跟踪

    • 会话跟踪引入的原因
      HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。当一个客户在多个页面间切换时,服务器会保存该用户的信息。
    • Cookie
      Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用。
    • session
      在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象,然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户,所以Session是依赖Cookie的,如果Cookie被禁用,可以考虑URL重写和表单隐藏域。
    • url重写
      在URL中附加标识客户端的session ID
    • 隐藏表单域
      将字段隐藏在HTML表单中,但不在客户端显示
    • ip地址

    9. 从浏览器地址栏输入url到显示页面的步骤

      1. 在浏览器地址栏输入URL
      1. 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
      • 如果资源未缓存,发起新请求
      • 如果已缓存,足够新鲜直接提供给客户端,否则与服务器进行验证。
      • 检验新鲜通常有两个HTTP头进行控制ExpiresCache-Control
        • HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
        • HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
      1. 浏览器解析URL获取协议,主机,端口,path
      1. 浏览器组装HTTP(GET)请求报文
      1. 浏览器获取主机ip地址,过程如下:
      • 浏览器缓存
      • 本机缓存
      • hosts文件
      • 路由器缓存
      • ISP DNS缓存
      • DNS递归查询(可能存在负载均衡导致每次IP不一样)
      1. 打开一个socket与目标IP地址,端口建立TCP链接,三次握手如下:
      • 客户端发送一个TCP的SYN=1,Seq=X的包到服务器端口
      • 服务器发回SYN=1,ACK=X+1,Seq=Y的响应包
      • 客户端发送ACK=Y+1,Seq=Z
      1. TCP链接建立后发送HTTP请求
      1. 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
      1. 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
      1. 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
      1. 服务器发送响应报文
      1. 浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重用,关闭TCP连接的四次握手如下:
      • 主动方发送Fin=1,Seq= X报文
      • 被动方发送ACK=X+1报文
      • 被动方发送Fin=1,ACK=X+1,Seq=Y报文
      • 主动方发送ACK=Y+1报文
      1. 浏览器检查响应状态码
      1. 如果资源可缓存,进行缓存
      1. 对响应进行解码
      1. 根据资源类型决定如何处理(假设资源为HTML文档)
    • 17.解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释

      1. 构建DOM树
      • Tokenizing:将字符流解析为标记流
      • Lexing:词法分析将标记转换为对象并定义属性和规则
      • DOM construction:根据HTML标记关系将对象组成DOM树
      1. 解析过程中遇到图片、样式表、js文件,启动下载
      1. 构建CSSOM树
      • Tokenizing:字符流转换为标记流
      • Node:根据标记创建节点
      • CSSOM:节点创建CSSOM树
      1. 根据DOM树和CSSOM树构建渲染树
      • 从DOM树的根节点遍历所有可见节点,不可见节点包括:
        • scriptmeta本身不可见的标签
        • 被css隐藏的节点,如display: none
      • 对每一个可见节点,找到恰当的CSSOM规则并应用
      • 发布可视节点的内容和计算样式
      1. js解析如下:
      • 浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystateloading
      • HTML解析器遇到没有asyncdeferscript时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
      • 当解析器遇到设置了async属性的script时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
      • 当文档完成解析,document.readState变成interactive
      • 所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
      • 浏览器在Document对象上触发DOMContentLoaded事件
      • 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
      1. 显示页面(HTML解析过程中会逐步显示页面)

    10. 浏览器缓存

    • 浏览器缓存(Brower Caching)是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档
    • 优点
      • 减少了冗余的数据传输
      • 减少了服务器的负担
      • 大大提升了网站的性能
      • 加快了客户端加载网页的速度
    • 浏览器缓存分为强缓存协商缓存,当客户端第一次请求发生后,再次请求某个资源时,获取缓存的流程如下:
      1. 先获取该资源缓存的header信息,根据其中的expires和cache-control判断是否命中强缓存,若命中则直接从缓存中获取资源,本次请求不会与服务器进行通信
      2. 如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息,服务器据此来对比结果是否命中协商缓存,若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容(304),它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容
    • 强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源; 区别是,强缓存不对发送请求到服务器,但协商缓存会
    • 当协商缓存也没命中时,服务器就会将资源发送回客户端
    • ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存
    • f5刷新网页时,跳过强缓存,但是会检查协商缓存
    • 强缓存
      强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间
      • Expires(该字段是 http1.0 时的规范,值为一个绝对时间的 GMT 格式的时间字符串,代表缓存资源的过期时间),这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。
      • Cache-Control:max-age(该字段是 http1.1的规范,强缓存利用其 max-age 值来判断缓存资源的最大生命周期,它的值单位为秒,相对时间)cache-control除了该字段外,还有下面几个比较常用的设置值:
        • no-cache:缓存要服务器验证才可以使用
        • no-store:禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源
        • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器
        • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存
      • 同时启用的时候Cache-Control优先级高
    • 协商缓存
      • 协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段
      • Last-Modified(值为资源最后更新时间,随服务器response返回)
      • If-Modified-Since(通过比较两个时间来判断资源在两次请求期间是否有过修改,如果没有修改,则命中协商缓存,返回304,并且不会返回资源内容和Last-Modified)
      • ETag(表示资源内容的唯一标识,随服务器response返回)
      • If-None-Match(服务器通过比较请求头部的If-None-Match与当前资源的ETag是否一致来判断资源是否在两次请求之间有过修改,如果没有修改,则命中协商缓存,服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化)
      • Last-ModifiedETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

    11. 浏览器存储

    特性 cookie localStorage sessionStorage indexDB
    数据生命周期 一般由服务器生成,可设置过期时间 除非被清理否则一直存在 页面关闭即被清理 除非被清理否则一直存在
    数据存储大小 4K 5M 5M 无限
    与服务端通信 每次携带在header中 不参与 不参与 不参与
    • cookie的本职工作并非是本地存储,而是状态维持

    12. SEO(搜索引擎优化)

    • 合理的titledescriptionkeywords:搜索对三项的权重逐个减小,title值强调重点,而且要靠前,不同页面title要有所不同;description把页面内容高度概括,长度合适,不同页面description有所不同;keywords列举出重要关键词
    • 语义化的HTML代码,让搜索引擎容易理解网页
    • 重要内容HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取
    • 重要内容不要用js输出:爬虫不会执行js获取内容
    • 少用iframe:搜索引擎不会抓取iframe中的内容
    • 非装饰性图片必须加alt
    • 提高网站速度:网站速度是搜索引擎排序的一个重要指标

    13. 渲染优化

    • 禁止使用iframe
    • 禁止使用gif图片实现loading效果(降低CPU消耗,提升渲染性能)
    • 使用CSS3动画代替JS动画(尽可能避免重绘重排以及回流)
    • 对于一些小图标,可以使用base64位编码,以减少网络请求
    • 页面头部的<script></script> 会阻塞页面;(因为 Renderer进程中 JS线程和渲染线程是互斥的)
    • 页面中空的 hrefsrc 会阻塞页面其他资源的加载 (阻塞下载进程)
    • 网页gzipCDN托管,data缓存,图片服务器
    • 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
    • innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
    • 当需要设置的样式很多时设置className而不是直接操作style
    • 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作
    • 图片预加载,将样式表放在顶部,将脚本放在底部加上时间戳

    14. 预解析、预加载和预渲染

    • 预解析
    • DNS Prefetch 是一种DNS 预解析技术,当浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在单击当前网页中的连接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。
    • 默认情况下浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的 DNS Prefetch。如果想对页面中没有出现的域进行预获取,那么就要使用显示的 DNS Prefetch 了。
    • DNS Prefetch 推荐放在 <meta charset="UTF-8"> 后面。具体使用方法如下:
    <meta  http-equiv="x-dns-prefetch-control" content="on">
    <link  rel="dns-prefetch" href="//www.zhix.net">
    <link  rel="dns-prefetch" href="//api.share.zhix.net">
    <link  rel="dns-prefetch" href="//bdimg.share.zhix.net">
    
    • 虽然使用 DNS Prefetch 能够加快页面的解析速度,但是也不能滥用,因为有开发者指出 禁用DNS 预读取能节省每月100亿的DNS查询
    • 如果需要禁止隐式的 DNS Prefetch,可以使用以下的标签:
    <meta  http-equiv="x-dns-prefetch-control" content="off">
    
    • 预加载
      • 资源预加载是另一个性能优化技术,可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到
      • 预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源
      • 和懒加载对比主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力
    <link rel="preload" as="script" href="super-important.js">
    <link rel="preload" as="style" href="critical.css">
    
    • 预渲染
      • 预渲染类似于在一个隐藏的 tab 页中打开了某个链接 – 将下载所有资源、创建 DOM 结构、完成页面布局、应用 CSS 样式和执行 JavaScript 脚本等。当用户真正访问该链接时,隐藏的页面就切换为可见,使页面看起来就是瞬间加载完成一样。
    <link rel="prerender" href="http://example.com"> 
    

    15. 浏览器架构与内核

    • 浏览器架构
      • 用户界面
      • 主进程
      • 内核
        • 渲染引擎
        • JS引擎
        • 执行栈
      • 事件触发线程
        • 消息队列
        • 微任务
        • 宏任务
      • 网络异步线程
      • 定时器线程
    • 浏览器内核
      • 渲染引擎(layout engineerRendering Engine)和JS引擎
      • 渲染引擎:负责取得网页的内容(HTMLXML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。
      • JS引擎:解析和执行javascript来实现网页的动态效果
      • 最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎
    • 各大浏览器内核

    1、IE浏览器内核:Trident内核,也是俗称的IE内核;
    2、Chrome浏览器内核:统称为Chromium内核或Chrome内核,以前是Webkit内核,现在是Blink内核;
    3、Firefox浏览器内核:Gecko内核,俗称Firefox内核;
    4、Safari浏览器内核:Webkit内核;
    5、Opera浏览器内核:最初是自己的Presto内核,后来是Webkit,现在是Blink内核;
    6、360浏览器、猎豹浏览器内核:IE+Chrome双内核;
    7、搜狗、遨游、QQ浏览器内核: Trident(兼容模式)+Webkit(高速模式)﹔
    8、百度浏览器、世界之窗内核:IE内核;
    9、2345浏览器内核:以前是IE内核,现在也是IE+Chrome双内核;


    16. Service Worker

    • Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全
    • Service Worker 实现缓存功能一般分为三个步骤
      • 首先注册 Service Worker
      • 然后监听到 install 事件以后就可以缓存需要的文件
      • 在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。
    • 以下是步骤的实现:
    //index.js
    if (navigator.serviceWorker) {
      navigator.serviceworker
        .register('sw.js')
        .then(function(registration) {
          console.log('service worker 注册成功')
        })
        .catch(function(err) {
          console.log('servcie worker 注册失败')
        })
    }
    // sw.js 监听install事件,回调中缓存所需文件
    self.addEventListener('install', e => {
      e.waitUntil(
        caches.open('my-cache').then(function(cache) {
          return cache.addAll(['./index.html', './index.js'])
        })
      )
    })
    //拦替所有请求事件, 如果缓存中已经有请求的数据就直接用缓存,否则去请求数据
    self.addEventListener('fetch', e =>{
      e.respondWith(
        caches.match(e.request).then(function(response){
          if (response){
            return response
          }
          console.log('fetch source')
        })
      )
    })
    

    17. Token

    • 服务器生成的用来做身份验证的字符串。服务器端拿到登录数据之后做数字签名和加密,得到字符串作为token返回给浏览器,客户端存储token并在每次请求时带上token,服务器接收到之后做解密和签名认证,验证有效性就能辨识用户身份(所以登录数据存在浏览器(但为了安全,token中不会存敏感信息,并且需要设置有效期)
    • token需要在每次请求中携带,需要把token放在http请求的请求头中
    • 基于token的用户认证的特点是服务器无状态,服务端不需要存放登录数据,用解密token的时间换存登录数据的空间,也减少了查数据库的次数

    18. webpack

    • WebPack 是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTMLJavascriptCSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后生成优化且合并后的静态资源

    19. gulp是什么

    • gulp是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成
    • gulp的核心概念:流
    • 流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向
    • gulp正是通过流和代码优于配置的策略来尽量简化任务编写的工作
    • gulp的特点:
      • 易于使用: 通过代码优于配置的策略,gulp 让简单的任务简单,复杂的任务可管理
      • 构建快速: 利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作
      • 易于学习: 通过最少的 API,掌握 gulp 毫不费力,构建工作尽在掌握:如同一系列流管道

    20. 渐进增强和优雅降级

    • 渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
    • 优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
    • 区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带

    21. 为什么利用多个域名来存储网站资源

    • CDN缓存更方便
    • 突破浏览器并发限制
    • 节约cookie带宽
    • 节约主域名的连接数,优化页面响应速度
    • 对于UGC的内容和主站隔离,防止不必要的安全问题(上传js窃取主站cookie之类的)。正是这个原因要求用户内容的域名必须不是自己主站的子域名,而是一个完全独立的第三方域名

    22. 网页制作会用到的图片格式

    • pngjpeggifsvg
    • WebpWebP格式是谷歌开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有jpeg的2/3,并能节省大量的服务器带宽资源和数据空间。在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小40%
    • Apng:全称是“Animated Portable Network Graphics”, 是PNG的位图动画扩展,可以实现png格式的动态图片效果。有望代替GIF成为下一代动态图标准

    23. 负载均衡

    • 多台服务器共同协作,不让其中某台或几台超额工作,发挥服务器的最大作用
    • http重定向负载均衡:有一台重定向服务器,根据用户的HTTP请求计算一台应用集群中服务器的地址,并将此地址写入HTTP重定向响应中返回给用户
      优点:实现简单
      缺点:需要请求两次服务器才能完成;重定向服务器易成为瓶颈;如果重定向服务器出故障,站点就会瘫痪;不利于网站的SEO
    • dns域名解析负载均衡:利用DNS处理域名解析请求的同时进行负载均衡处理,在DNS中配置多个A记录,每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回
      优点:将负载均衡的工作转交给DNS,省掉了网站管理维护负载均衡服务器的麻烦,同时可以使用智能DNS基于地理位置或者ISP来做域名解析,用户将会得到距离最近或者速度最快的服务器地址,加快访问速度,改善性能
      缺点:DNS是多级解析,每一级都会缓存DNS记录,如果某个服务器变动了,DNS记录更新的时间将会很长
    • 反向代理负载均衡(应用层负载均衡):使用反向代理服务器,将请求转发给内部网络上的服务器,并将结果返回客户端,最终目标服务器对客户端透明,缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈
    • 网络层负载均衡(IP负载均衡):在网络层通过修改请求目标地址进行负载均衡,请求达到负载均衡服务器后,由负载均衡服务器获取网络数据包,根据负载均衡算法得到一台真实web服务器的地址,修改请求的目的地址到这台真实的web服务器地址,等到web服务器处理完成后,响应数据包回到负载均衡服务器,再将数据包源地址修改为自身的IP地址发送给用户浏览器
    • 数据链路层负载均衡:数据分发过程中不修改IP地址,只修改mac地址,通过配置真实物理服务器集群所有机器虚拟IP和负载均衡服务器IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的

    24. CDN

    • 内容分发网络,基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
    • 要提高访问速度,最简单的做法当然就是多设置几个服务器,让终端用户离服务器“更近”。典型的例子是各类下载网站在不同地域不同运营商设置镜像站,或者是像Google设置多个数据中心。但是问题在于,一是多地部署时的困难,二是一致性没法保障,三则是管理困难、成本很高。
    • CDN是一种公共服务,有很多台位于不同地域、接入不同运营商的服务器,而所谓的使用CDN实质上就是让CDN作为网站的门面,用户访问到的是CDN服务器,而不是直接访问到网站。由于CDN内部对TCP的优化、对静态资源的缓存、预取,加上用户访问CDN时,会被智能地分配到最近的节点,降低大量延迟,让访问速度可以得到很大提升。
    • CDN做了两件事,一是让用户访问最近的节点,二是从缓存或者源站获取资源



    25. 前后端路由的区别

    • 前端路由

    把不同路由对应的不同内容掌握在前端,如vue中的vue-router、react的ReactRouter等。出现在单页面应用中,页面中公共部分不变,只改变部分内容的使用。路由切换时根据不同的路由动态加载不同的组件,不刷新页面。
    优点:实现前后端的分离,缓解服务器压力,不需要每次从服务器获取,快速展现给用户,用户体验更好。

    • 后端路由

    见于多页面应用中。每次都向后台服务器发出请求,服务器响应请求,在后台拼接html文件传给前端显示, 返回不同的页面,浏览器会刷新页面。


    26. WEB标准以及W3C标准

    • web标准简单来说可以分为结构、表现和行为。web标准一般是将该三部分独立分开,使其更具有模块化。但一般产生行为时,就会有结构或者表现的变化,也使这三者的界限并不那么清晰
    • W3C对web标准提出了规范化的要求,也就是在实际编程中的一些代码规范:包含如下几点
    • 对于结构(标签规范可以提高搜索引擎对页面的抓取效率,对SEO很有帮助)
      • 标签字母要小写
      • 标签要闭合
      • 标签不允许随意嵌套
    • 对于cssjs
      • 尽量使用外链css样式表和js脚本。使结构、表现和行为分为三块,符合规范。同时提高页面渲染速度,提高用户的体验。
      • 样式尽量少用行间样式表,使结构与表现分离,标签的id和class等属性命名要做到见文知义,标签越少,加载越快,用户体验提高,代码维护简单,便于改版
      • 不需要变动页面内容,便可提供打印版本而不需要复制内容,提高网站易用性

    27. web标准的可用性、可访问性、可维护性

    • 可用性Usability:产品是否容易上手,用户能否完成任务,效率如何,以及这过程中用户的主观感受可好,是从用户的角度来看产品的质量。可用性好意味着产品质量高,是企业的核心竞争力
    • 可维护性Maintainability:一般包含两个层次,一是当系统出现问题时,快速定位并解决问题的成本,成本低则可维护性好。二是代码是否容易被人理解,是否容易修改和增强功能。
    • 可访问性Accessibility:Web内容对于残障用户的可阅读和可理解性,提高可访问性也能让普通用户更容易理解Web内容,具体考虑以下两个方面:
      • 无论用户是否残障,都要通过用户代理(User Agent)来访问Web内容。因此要提高可访问性,首先得考虑各种用户代理 :桌面浏览器、语音浏览器、移动电话、车载个人电脑等
      • 还要考虑用户访问Web内容时的环境限制 。比如:嘈杂的环境、过暗或过亮的房间、或者是免提等各种情况
    • 可访问性四个标准
      • 可感知:使用者可以通过适合自己的媒体来获知网页内容。比如应当让盲人得以收听页面内容。
      • 可操作:使用者可以与 web 应用程序或内容进行交互。例如,用户可以不用鼠标也能与某个网站进行交互,并且可以通过屏幕阅读器来进行导航。
      • 可理解:使用者可以弄懂页面内容和用户界面。例如,正文不应该比它需要的更加复杂,且网站应以可预测的方式来运行。
      • 健壮性:所提供的一切服务都应当不受平台或操作系统的限制。例如,不同设备上的浏览器能够一起使用网站,且导航应该是一致的。

    28. 谈谈你对重构的理解

    • 网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI
    • 对于传统的网站来说重构通常是:
      • 表格table布局改为DIV+CSS
      • 使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
      • 对于移动平台的优化
      • 针对于SEO进行优化

    相关文章

      网友评论

        本文标题:前端面试常见问题——Web篇

        本文链接:https://www.haomeiwen.com/subject/wscmektx.html