面试提纲汇总

Posted by Asser's Blog on August 8, 2019

浏览器机制

  • 浏览器的线程、进程梳理

    进程和线程进程相当于工厂,线程相当于工人。一个工厂内有一个或者多个工人。工厂拥有自己的资源(比如cpu,内存)浏览器有多个进程,基本上每个页面都是一个进程,其他的还有browser进程(负责页面交互显示,前进后退。管理各个tab页面进程的创建和销毁),网络资源进程(下载资源),第三方插件进程,gpu进程(至多一个),浏览器渲染进程

  • 浏览器渲染进程包括:
    • js引擎线程(所谓的js是单线程)
    • gui用户界面渲染线程(跟js引擎互斥)
    • 事件触发线程(setTimeout, 点击事件,ajax请求等)
    • 定时器线程 (W3C的HTML标准中规定,setTimeout中低与4ms的时间间隔算为4ms)
    • 异步请求线程
  • webWorker

    向浏览器申请子线程用于运算处理,跟主线程通信使用postMessage API(使用时要保证协议,端口,document.domain全部相同才可以通信)。可用于处理高耗时计算

  • postMessage

    使用 window.addEventListener(‘message’, handler, false) 进行监听数据传输,为了保证安全通过event的origin和source属性来判断 *** <font color=red>webWorker没有任何权限操作dom</font>

  • shareWorker(兼容性极差)

    实现多个tab页面之间的通信

  • 浏览器的捕获和冒泡过程、如何禁止浏览器的默认行为、click事件、mouse事件、touch事件的执行顺序
    • 概念:

      “DOM2级事件”规定事件流包括三个阶段,事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的事件捕获,为截获事件提供了机会。然后是实际的目标接收了事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。(总结:从外到内再从内到外)

    • 禁止冒泡:

      w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

    • 取消默认事件:

      w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;

    • event.stopImmediatePropagation

      如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法,则当前元素剩下的监听函数将不会被执行。(译者注:注意区别 event.stopPropagation )

  • 浏览器的数据存储(localStorage、sessionStorage、indexedDB、cookie)
  • 浏览器的跨域问题以及解决方案

    跨域:协议,端口,域名任意一个不同

  • async和defer脚本的区别

  • historyAPI

  • 浏览器刷新率

    60Hz,即1/60s刷新一次。

    用setTimeout写动画会出现问题。应使用window.requestAnimationFrame(callback)的方式

    监听动画执行使用动画监听事件

    • DOM.addEventListener(‘animationstart’) // css动画开始后触发
    • ‘animationiteration’ // css动画重复播放时触发
    • ‘animationend’ // css动画结束时触

js、css

js:

  • 基本类型与引用类型
    • typeof
    • instanceof
    • Object.prototype.toString.call()
  • this指向问题(call, apply, bind)

  • 面向对象问题
    • es5、es6实现继承
    • 原型链机制
  • 闭包
  • 垃圾回收机制
  • 事件循环
    • 概念: + js一直在执行一个类似于while true的循环。事件任务分为宏任务和微任务。执行顺序为宏任务 -> 微任务 -> 宏任务 -> 微任务 …
    • 宏任务包括: + IO操作(ajax、点击事件等)、setTimeout、setInterval、setImmediate、requestAnimationFrame、 postMessage(在vue2.0的$nextTick中,就是优先使用微任务:promise再考虑宏任务setImmediate和MessageChannel的postMessage,最后才考虑使用setTimeout)
    • 微任务包括: + process.nextTick、promise、MutationObserver(监听dom变化)、Object.observe
  • 隐式类型转换
    • [] == false 和 !![] == true
    • a == 1 && a== 2 && a == 3
  • 常用API(字符串,数组,对象,dom、 Date对象、 math对象)

  • 正则表达式

  • es6
    • 箭头函数与普通函数对比

      无法使用new this指向考点

    • 手写promise
    • map、set、proxy、迭代器函数、装饰器(使用es5实现?)
  • ajax
    • 监听xml.onreadystatechange事件 + xml.readystate + 0 // 代理被创建,open方法未调用 + 1 // open()被调用 + 2 // send()方法被调用,响应头被接收 + 3 // 响应体正在被接收 + 4 // 数据传输完成
    • xml.status 为响应中的状态码
    • xml.upload 返回一个XMLHttpRequestUpload对象,监听该对象的‘progress’事件,可以获取上传进度

    图片上传进度获取

  • setTimeout和setInterval底层的区别
setInterval(() => {
	fn() // 当这段代码执行的时间超过100ms时会怎么样
}, 100)

答:

假设在5ms时开始setInterval,设定105ms执行function block。但是由于205ms时,function block没有执行完毕,导致原本预定在205执行的function block被滞留,而js只允许一份function block被滞留,从而导致代码段执行丢失(应该是一个setInterval只允许一个,未试验)。 解决方案:使用setTimeout代替setInterval

css:

  • 双飞翼布局实现方案
  • 垂直水平居中
  • 盒模型
  • BFC
  • 伪元素、伪类选择器
  • css3 阴影

常用框架

  • vue的生命周期

  • vue的父子组件、兄弟组件传值

  • 介绍vuex

  • vue中mixin和extend的区别

  • vue-router部分
    • 实现原理
    • hash和history如何实现监听
      • window.onhashchange和window.onpopstate (兼容性:当后端不做配置的时候,用history模式按f5刷新,会直接请求,有可能出现404。用hash模式就不存在这个问题)
    • 导航钩子
  • vue的双向绑定原理
    • Object.defineProperty() 进行getter和setter的劫持 + 发布订阅模式
  • vue2.0无法根据index修改数组的方案优化
    • 利用proxy实现vue的框架优化
  • vue的diff算法

  • virtualDom

  • keepAlive

  • vue3.0新特性

  • vue服务端渲染

网络

  • cookie和session

  • 常见以及非常见http code
    • 1xx(临时响应): 表示临时响应并需要请求者继续操作
      • 100 (继续)
        • 请求者应当继续请求,服务器返回此状态码表示已经接收到了第一部分,正在等待其余部分
      • 101 (切换协议)
        • 请求者已要求服务器切换协议,服务器已确认并准备切换
    • 2xx (成功)
      • 200(成功)
        • 服务器已经成功处理请求
      • 201(已经创建)
        • 请求成功并且服务器已经创建了新的资源
      • 202(已接受)
        • 服务器已经接受了请求,但是尚未处理
      • 203(非授权信息)
        • 服务器已经成功处理了请求,但返回的信息可能来自另一个来源
    • 3xx(重定向)
      • 301(永久移动)
      • 302(临时移动)
      • 303(查看其他位置): 请求者应当对不同位置使用单独的get请求来检索响应时,服务器返回此代码
      • 304 (not modified): 被请求的网页未发生修改,可以直接读取浏览器缓存
      • 305(使用代理): 请求者只能通过代理访问请求的网页(此时请求者应使用代理)
      • 307 (临时重定向): 服务器目前从不同位置的网页响应请求,但请求者应继续使用原来位置来进行以后的请求
    • 4xx(请求错误)
      • 400(错误请求): 服务器不理解请求的语法
      • 401(未授权): 请求要求身份验证
      • 403(forbidden): 禁止访问~~~
      • 405(方法不被允许): 禁用了请求中指定的方法
    • 5xx(服务端错误)
      • 500(服务器内部错误)
      • 502(bad gate): 网关服务器从上游服务器接收到无效响应
      • 503(不可用服务器)
      • 504(网关超时)
      • 505不支持所用的http协议版本

      比较有趣的http状态码记忆链接

  • 缓存策略
    • 强缓存(仅用于客户端)
      • cache-control
        • max-age public private no-cache no-store
          • public表示可以被浏览器和代理服务器缓存,代理服务器一般可用nginx来做
          • immutable 如果cahe-control:max-age=315360000,public再加个immutable的话,就算用户刷新页面,浏览器也不会发起请求去服务,浏览器会直接从本地磁盘或者内存中读取缓存并返回200状态,看上图的红色框(from memory cache)
          • private 只让客户端可以缓存该资源;代理服务器不缓存
          • no-cache
            • 跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。
          • no-store
            • 不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了
    • 协商缓存(用于服务器和客户端相互交互)
      • etag:每个文件有一个,改动文件了就变了,就是个文件hash
      • last-modified:文件的修改时间,精确到秒(当文件被访问时,文件的last-modified会发生变化,所以并不准确)

      • 每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上,服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified,这时候对客户端来说,每次请求都是要进行协商缓存了
    • 协商缓存流程:
      • 服务器资源未过期:发请求–>看资源是否过期–>过期–>请求服务器–>服务器对比资源是否真的过期–>没过期–>返回304状态码–>客户端用缓存的老资源。

      • 服务器资源过期:发请求–>看资源是否过期–>过期–>请求服务器–>服务器对比资源是否真的过期–>过期–>返回200状态码–>客户端如第一次接收该资源一样,记下它的cache-control中的max-age、etag、last-modified等。

  • 从输入url到页面呈现发生了什么
    1. url -> ip DNS解析
    2. 发起http请求,涉及tcp/ip协议三次握手,假如是https还有一个证书交换,ssl
    3. 请求回来的字节流被浏览器进行词法解析,加载head中的链接
    4. html字符流被解析成dom树,进行渲染(domInteractive事件触发)
    5. css文件内容被解析成css树,对已有dom树进行渲染生成render树(domContentLoaded事件触发)
    6. 根据render树进行页面layout,确定dom元素的位置,大小
    7. 进行painting,绘制页面像素信息
    8. 浏览器根据上述信息发送给gpu,gpu进行信息合成,显示在屏幕上
    9. 下载对应图片完成(domComplete事件触发)
    10. 直到现在,js引擎执行load事件(执行加载完的js脚本(js线程和页面渲染线程互斥,所以script要贴着</body>尽量放下面))

页面性能

  • 内存泄漏如何监听

  • 页面启用硬件加速

  • 页面的repaint和reflow
    • reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow 会从 <html> 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。

    • repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

      注意:display:none的节点不会被加入Render Tree,而visibility: hidden则会,所以display:none会触发reflow,visibility: hidden会触发repaint。

  • 页面性能优化点总结
    • 性能测量
      • window.performance、 console.time() && console.timeEnd()

      • first paint性能优化

        • 有缓存
          • 优化点:页面缓存策略
        • 无缓存
          1. url -> ip DNS解析
            • 优化点:
              • 使用dns预解析
            • 由客户端控制主动通过请求dns获取域名ip,不走系统dns解析(具体方案待查)
          2. http请求是基于tcp协议的,涉及tcp协议三次握手。假如使用https还包括ssl证书交换
            • 优化点:
              1. 压缩文件大小
              2. 浏览器有并发最大连接数,合并js和css至html中
              3. 由服务端升级到http2(避免重复建立tcp连接)
              4. 使用gzip
              5. 使用cdn
              6. css spirite
              7. 图片懒加载,异步加载
              8. js根据路由异步加载(框架)使用defer和async(原生 两者的不同?)
              9. 小型图片使用data-uri
    • 前端无限滚动下拉加载设计
      • 问题分析:
        1. dom操作的性能消耗,而且dom操作是阻塞的。当一个dom操作在进行时,用户和页面交互无法进行(除了滚动页面)
        2. 视口外的图片的加载
        3. 滚动问题的节流和防抖
      • 解决方案:
        1. 在viewport外的图片实现懒加载(需要一个阈值,在用户滚动到页面底部之前稍微提前一点进行加载)

        2. 滚动问题(截流和防抖)

          1. Throttle允许我们限制激活响应的数量。我们可以限制每秒回调的数量。反过来,也就是说在激活下一个回调之前要等待多少时间;

          2. Debounce意味着当事件发生时,我们不会立即激活回调。相反,我们等待一定的时间并检查相同的事件是否再次触发。如果是,我们重置定时器,并再次等待。如果在等待期间没有发生相同的事件,我们就立即激活回调。
          3. 缓存ajax请求以及对应内容(by Asser)
          4. 将移除视口的dom进行remove (by Asser)
          5. 将每次拉取到的一批数据放在documentFragment里面再一起插入dom。减少页面回流 (by Asser)

工程化

  • webpack
    • 主要分为入口,出口,loader、插件和模式五个部分。由于webpack只识别js,loader将入口文件直接引入和间接引入的非js文件,转化为webpack能处理的模块(module),

    • loader有两个参数,test和use。test表示匹配到的文件,可以使用正则。use表示使用的loader。
    • loader开发采用单一职责模式,基本loader都是通过链式调用的方式,只需要关心输入和输出。第一个loader处理原内容,之后每个loader处理的都是上一个loader的处理后的结果。(说白了就是一个函数来着)
    • plugins需要通过require引用,然后放在plugins数组里,数组的每个item都是plugin文件的实例。在编译的过程中,webpack会在特定的时间点广播特定时间,然后plugin监听到对应时间就会执行对应逻辑。(plugin的目的主要是实现loader无法做到的其他事情)
      class TestPlugin {
        constructor(successCb, failCb) {
        this.successCb = successCb
        this.failCb = failCb
        }
        apply(compiler) {
        compiler.plugin('done', state => {
            this.successCb(state)
        })
        compiler.plugin('failed', state => {
            this.failCb(state)
        })
        }
      }
      
  • 在编写plugin时最常用的就是compiler和compilation。 + compiler可以理解为webpack实例,在webpack被启动的时候被实例化传给plugin。包含loaders, options,plugins这些信息。相当于webpack整个生命周期 + compilation表示当前的模块资源,变化的文件等。相当于一次新的编译
    <font color=red>注意传给plugin的compiler和compilation都是同一个对象的引用!</font></br>

  • 常用webpack plugin loader
    • webpack uglifyjsPlugin, CommonChunkPlugin, extraTextplugin

    • webpack按需加载内部实现原理

安全

  • xss原理以及防御
  • csrf原理以及防御

计算机基础

  • 内存存储(堆、栈)
  • 排序算法
    • 冒泡
      function bubbleSort(arr) {
        for (let i = 0, len = arr.length; i < len - 1; i++) {
        for (let j = i + 1; j < len; j++) {
            if (arr[i] > arr[j]) {
                let temp = arr[i]
                arr[i] = arr[j]
                arr[j] = temp
            }
        }
        }
      } 
      
  • 选择

  • 插入

  • 快速

  • 合并

  • Unicode和UTF-8字符串编码解码原理
  • base64和二进制的不同

面试后补充:

+ dll-plugin

+ file-uploader 上传失败的监听

+ redux和vuex的对比

+ hash和history API的兼容性问题

+ jsonp的缺陷

+ vue3.0的新特性

+ node服务端渲染

+ node大文件上传

+ nextTick实现原理

参考链接:

  1. 面试方向
  2. 面试汇总

被虐:

  • vw,vh实现原理
  • https 对称&非对称加密原理
  • jsBridge实现方案(除开现有的注入)现有的注入底层的实现原理
  • js浮点数bug内存存储原因
  • 常见排序算法 时间空间复杂度如何计算
  • Object._proto_
  • typeOf Object
  • 移动端适配方案(除开rem还有其他的吗)
  • webpack打包之后的成果,pollyFill如何实现浏览器兼容
  • leetCode编程练习
  • 迭代器函数的使用(实现async await的封装)
  • es6导入导出和amd导入导出的区别

可落地的发展方向:

  • 一次编译多端实现(rn ,weex, flutter,小程序等)
  • webpack自动化
  • node后台方向
  • polyFill手动实现

大厂要求

  • 扎实的基础
  • 对新技术时刻保持敏锐的嗅觉
  • 对已经实现的技术底层原理保持好奇心

新技术 && 新特性

  • webComponents
  • GraphQL
  • serverLess
  • PWA桌面应用(electron)
  • TypeScript
  • WebAssembly
  • Vue3.0
  • Webpack5.0
  • Http2.0

前端架构

  • 框架技术选型
  • 性能监控以及异常监控
  • 前后端分离