# 技术面

面试技巧

  • 知识面要广
  • 理解要深刻
  • 内心要诚实
  • 态度要谦虚
  • 回答要灵活
  • 要学会赞美

本篇重点内容:

  • 渲染机制
  • JS运行机制
  • 页面性能
  • 错误监控

# 渲染机制

  • 什么是DOCTYPE及作用

    DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或者(X)HTML文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析,以及切换浏览器模式。

    DOCTYPE是用来声明文档类型和DTD规范的,一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时便会出一些差错。

    HTML5
    <!DOCTYPE html>
    
    HTML 4.01 Strict # 该DTD包含所有HTML元素和属性,但不包括展示性和弃用的元素(比如font)
    <!DOCTYPE HTML PUBLIC "-//W3C//DTC HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    
    HTML 4.01 Transitional # 该DTD包含所有HTML元素和属性,但包括展示性和弃用的元素(比如font)
    <!DOCTYPE HTML PUBLIC "-//W3C//DTC HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
    
  • 浏览器渲染过程

    渲染机制

    DOM tree:

    DOMtree

    CSS tree:

    CSStree

    Render tree:

    RenderTree

    Layout:

    Layout

  • 重排Reflow

    1. 定义:DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览吕根据各种样式来计算并根据计算结果将元素放到它该出现的问题,这个过程称之为reflow。

    2. 触发Reflow:

      • 当你增加、删除、修改DOM结点时,会导致Reflow或Repaint
      • 当你移动DOM的位置,或是搞个动画的时候
      • 当你修改CSS样式的时候
      • 当你Resize窗口的时候(移动端没有这个问题),或者是滚动的时候
      • 当你修改网页的

      最常问:如何减少Reflow?或者避免Reflow?

  • 重绘Repaint

    1. 定义:当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。

    页面要呈现的内容,通通都绘制到页面上。

    1. 触发Repaint

      • DOM改动
      • CSS改动

      最常问:如何避免最小程序的Repaint?

  • 布局Layout

# JS运行机制

案例来说明:

console.log(1)
setTimeout(function(){
  console.log(3)
},0)
console.log(2)

输出:
123

js是单线程,那么异步在js中是如何实现的呢?其实,就是任务队列。

setTimeout是一个异步任务,异步任务要挂起。

console.log('A')
while(true){
  
}
console.log('B')
输出:
A # 页面会卡死

如果是下面:

console.log('A')
setTimeout(function(){
  console.log('B')
},0)
while(1){
  
}
输出:
A # 页面会卡死

另外再来看看下面的题目:

for(var i=0; i < 4; i++) {
  setTimeout(function(){
    console.log(i)
  },1000)
}
输出:
4
4
4
4
# 总运行时间1s

有哪些异步任务?

  • setTimeout和setInterval
  • DOM事件
  • ES6中的Promise

# 页面性能

题目:提升页面性能的方法有哪些?

  1. 资源压缩合并,减少HTTP请求(开启gzip)

  2. 非核心代码异步加载—>异步加载方式—>异步加载的区别

  3. 利用浏览器缓存—>缓存的分类—>缓存的原理

  4. 使用CDN

  5. 预解析DNS

    <meta http-equiv="x-dns-prefetch-control" content="on">
    <link rel="dns-prefetch" href="//host_name_to_prefetch.com">
    

关于异步加载

  1. 异步加载的方式
    • 动态脚本加载
    • defer
    • async
  2. 异步加载的区别
    • defer是在HTML解析完之后才会执行,如果是多个,按照加载的顺序依次执行
    • async是在加载完成之后立即执行,如果是多个,执行顺序和加载顺序无关

示例代码:

Index.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Defer</title>
  <script src="./defer1.js" defer></script>
  <script src="./defer2.js" defer></script>
</head>
<body>
<div>
  test
</div>
<script type="text/javascript">
  document.write('<span>write</span>')
</script>
<script>
  for(var i=0; i < 200000; i++) {
    if (i % 20000 === 0) {
      console.log(i)
    }
  }
</script>
</body>
</html>

两个Deferjs中只有一句console.log('defer')

同理,可以尝试一下async属性

关于缓存的分类

  1. 强缓存

    HTTP 头:

    Expires  Expires: Thu, 21 Jan 2017 23:39:02 GMT
    
    Cache-Control Cache-Control:max-age=3600
    
  2. 协商缓存

    Last-Modified If-Modified-Since Last-Modified: Web, 26 Jan 2017 00:35:11 GMT
    
    Etag If-None-Match
    

# 错误监控

  • 前端错误的分类

    1. 即时运行错误:代码错误
    2. 资源加载错误
  • 错误的捕获方式

    1. 即时运行错误的捕获方式

      (1) try….catch

      (2) window.onerror

      window.onerror只能捕获及时运行错误,不能捕获资源加载错误

    2. 资源加载错误的捕获方式

      (1) boject.onerror

      (2) performance.getEntries()

      # console窗口中执行
      
      performance.getEntries().foreach((item)=>{
      	console.log(item)
      })
      #即可以打印网页上加载的资源
      

      (3) Error事件捕获

      示例:

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Error</title>
        <script>
          window.addEventListener('error', function (e) {
            console.log('捕获', e)
          }, true)
        </script>
      </head>
      <body>
      <script src="//baidu.com/fdsfdsfds.js" charset="utf-8"></script>
      </body>
      </html>
      

      延伸:跨域的js运行错误可以捕获吗?错误提示什么,应用怎么处理?

      解析:跨域的js运行错误也是可以捕获的

      1. 在script标签增加crossorigin属性
      2. 设置资源响应头Access-Control-Allow-Origin:*
  • 上报错误的基本原理

    1. 采用Ajax通信的方式上报

    2. 利用Image对象上报

      // 只需要一行代码就可以实现
      (new Image().src='http://baidu.com/test?r=data')