前端面试题复习(2)-浏览器原理

61 阅读16分钟

浏览器安全

xss

概念

恶意代码注入攻击,盗取用户信息等。

攻击类型:存储型、反射型、DOM型。

存储型的恶意代码存在数据库里,当用户访问的页面有恶意代码的数据时,会执行脚本,做一些恶意操作,比如窃取数据、冒充用户行为

反射型的恶意代码存在URL里,用户打开url,服务器将恶意代码从url中取出并执行,调用目标网站接口执行将数据发送到攻击者服务器中

DOM的XSS是浏览器完成,上面两种都是服务端完成。

如果防御

  1. 代码中做到充分的转义,
  2. 使用CSP。一种内容安全策略,可以配置白名单指定能够加载执行的外部资源
    1. csp开启方式:一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设meta标签的方式
  3. 对一些敏感信息进行保护,比如cookie使用的http-only,验证码等。

CSRF

概念

跨站请求伪造攻击,利用cookie在同源请求中绕过用户登陆向服务器发送请求。

攻击类型:get类型、post类型、链接类型

如何防御

  1. 进行同源检测:通过refer判断是不是可以请求的页面
  2. 使用CSRF TOKEN进行验证
  3. 对cookie进行双重验证
  4. 设置cookie的时候设置samesite,限制cookie不能被第三方使用。

中间人攻击

攻击者和通讯的两端都建立联系,让两端以为在直接联系,在中间篡改信息

哪些可能引起安全问题

  1. 跨站脚本,XSS
  2. iframe的滥用
  3. 跨站点请求伪造(CSRF)
  4. 恶意第三方库

网络劫持有哪几种

  1. DNS劫持(违法)
  2. HTTP劫持(盛行),防护措施:https

进程与线程

概念

进程是资源分配的最小单位,线程是CPU调度的最小单位。

进程是运行在虚拟内存上的。

两者关系

  1. 线程执行出错,会导致进程崩溃
  2. 线程之间共享进程的数据
  3. 当一个进程关闭之后,操作系统会回收进程所占用的内存
  4. 进程之间的内容相互隔离。如果要通讯的话有单独的通讯机制

区别

  1. 切换时,资源、系统开销,进程都比较大、线程都比较小
  2. 通信,线程比较方便,进程比较麻烦需要通信机制

进程之间的通信

  1. 管道通信
  2. 消息队列通信
  3. 信号量通信
  4. 信号通信
  5. 共享内存通信
  6. 套接字通信

僵尸进程、孤儿进程

**僵尸进程:**子进程已结束父进程未结束,但父进程没有释放子进程的内存。这些子进程被叫做僵尸进程。

**孤儿进程:**父进程退出了,子进程还在运行。这些进程被叫做孤儿进程。释放方式:挂载在init进程上统一回收。

死锁

多个进程进行资源争夺出现僵局,(资源分为可剥夺资源、不可剥夺资源)

产生原因:

  1. 竞争资源:竞争不可剥夺资源和临时资源
  2. 进程间推进顺序非法。

chrome的浏览器包括:

  1. 1个浏览器主进程
  2. GPU进程
  3. 网络进程
  4. 多个渲染进程
  5. 多个插件进程

打开一个页面最少要 1-4 ,4个进程。 缺点:高资源占用;浏览器体系复杂,难以完全适配。

浏览器渲染进程中的线程有:GUI渲染线程、JS引擎线程、事件触发线程、定时器触发线程、异步http请求线程。

定时器触发请求:即setTimeout和setInterval;W3C在HTML标准中规定,定时器的定时时间不能小于4ms,如果是小于4ms,则默认为4ms。

浏览器之间多个标签页的通讯

通过中间件来进行通讯

  1. 利用网络,websocket协议
  2. 利用共享线程,shareWorker
  3. 监听localStorage,
  4. postMessage

service worker

运行在浏览器背后的独立线程。可用来实现缓存功能。 实现步骤:注册线程 => 监听到注册成功,缓存对应文件 => 拦截请求,如果文件已缓存,使用缓存,否则请求数据

浏览器缓存

强制缓存

浏览器初次请求页面,通过header头的 Expires 属性 和 Cache-Control 的设置来决定如何缓存资源。

  • Expires 表示 资源过期时间;http1.0 提出;
  • Cache-Control 是 http1.1 提出,由于 Expires 属性单一等缺点,出现这个属性。
    • Cache-Control可设置的字段:
      • public :表示可以被任何对象缓存
      • private :表示只能用户浏览器缓存,禁止代理服务器缓存
      • no-cache :对比服务器上的资源是否发生变化,如果未变化直接用缓存,会有协商缓存
      • no-store : 完全禁止缓存,协商缓存
      • max-age= :缓存最大有效期,单位为秒
      • s-maxage= : 优先级高于max-age=和Expires,仅适用于CDN
      • max-stale[=] : 表示用户愿意接受过期的资源,但不能超出给定的时间

一般来说设置一种就可以缓存,但是 Cache-Control 的优先级要高于 Expires。 如果强制缓存,就会直接下载;

协商缓存

命中协商缓存的条件:

  1. max-age=xxx 过期了
  2. no-store

命中协商缓存后 服务器发现资源未变化,会返回304,浏览器直接使用副本;变化直接返回资源。

协商缓存也可以通过 http 头信息中的 Etag 和 Last-Modified 属性 来设置。

  • Last-Modified :表示最后一次资源修改的时间;请求下一次会给服务器发送上次请求时文件修改的时间,以此来判断文件是否修改过。如果时间没变 返回 304;时间变了 返回新的资源。
    • 缺点:如果在秒级修改多次,时间没变,文件也不会变
  • Etag : 类似文件hash值,资源发生改变的时候,这个值也会改变。
    • 缺点:如果考虑负载平衡不建议用这个值 Etag 和 Last-Modified同时出现的时候,Etag优先级

强缓存和协商缓存区别

  1. 有缓存时,强缓存不会发送请求,协商缓存会发送一次请求

优点:可以减少请求,提高页面性能

点击刷新按钮或者按 F5、按 Ctrl+F5 (强制刷新)、地址栏回车有什么区别?

  1. 点击刷新按钮或者按 F5: 浏览器直接对本地的缓存文件过期,但是会带上If-Modifed-Since,If-None-Match,这就意味着服务器会对文件检查新鲜度,返回结果可能是 304,也有可能是 200。
  2. 用户按 Ctrl+F5(强制刷新): 浏览器不仅会对本地文件过期,而且不会带上If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是 200。
  3. 地址栏回车: 浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。

浏览器组成

理解: 展示页面。分为shell(菜单、工具栏等)和内核(识别程序)两部分

浏览器内核

  1. 渲染引擎
  2. js引擎

常见浏览器内核

  1. Trident:IE浏览器内核,久不维护,基本被废弃
  2. Gecko:火狐和flock的内核,功能强大但耗费内存
  3. Presto:Opera 曾经的内核,速度很快,但是丢失了一部分的兼容性
  4. Webkit:safari的内核,速度较快,兼容性也低;是KHTML的一个分支
  5. Blink:GOOGLE,Opera,共同的引擎,也是KHTML的一个分支

常见浏览器所用内核

  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 双内核了;
  10. UC 浏览器内核:这个众口不一,UC 说是他们自己研发的 U3 内核,但好像还是基于 Webkit 和 Trident ,还有说是基于火狐内核。

浏览器的主要组成部分

  1. 用户界面
  2. 浏览器引擎
  3. 呈现引擎
  4. 网络
  5. 用户界面后端
  6. js解释器
  7. 数据存储

浏览器渲染原理

浏览器渲染步骤

  1. 解析文档,将文档解析为带属性的 DOM 树。
  2. 解析CSS 将css解析为 cssM树
  3. 上面两个树,最后合成一个渲染树。只会有可见的元素,这个时候节点只知道大小颜色
  4. 生成渲染树后,根据渲染树推出节点的位置,这一步叫回流
  5. 然后对着渲染树进行绘制。 树不可能一次性生成完,而是生成一部分绘制一部分,有些可能还在下载。

浏览器渲染优化

  1. js的位置:不要讲script放在head、body中,放在</body>前,还有异步加载方式 defer或者async
  2. 针对css 有两种 link、@import。前者会增加线程下载,后者会阻塞渲染。style内嵌 直接渲染。
  3. cssom树,dom树的优化
    1. html文件代码层级不要太深
    2. 语义化标签
    3. cssD代码的层级,选择是从左向右解析的
  4. 减少回流和重绘:
    1. DOM 在低层次操作
    2. 不要用table布局
    3. 使用css表达式
    4. 少操作样式,尽量改类名
    5. 使用absolute或fixed。脱离文档流,改样式不会影响其他元素
    6. 避免频繁操作DOM,可以创建文档片段,加在文档里
    7. 不可见元素可以设置display:none,需要展示的时候展示出来
    8. 将相同的读操作或写操作放一起,不要穿插放,这样浏览器会把相同的操作执行回流一次(浏览器自身的优化:渲染队列)

渲染时遇到js如何处理

会阻塞渲染,直到js执行完; 如果有defer或async异步加载,defer会并行下载,DOM数据结束后执行。async会并行下载,下载后阻断渲染直接执行

文档预解析

Webkit 和 Firefox 做了优化,js执行时,另一个线程解析剩下的文档,比如外部资源等等。但不会解析dom树

css如何阻塞文档解析

js中有css样式会阻塞文档解析。这种情况下会先css解析,再js执行,再文档解析

优化关键渲染路径

(1)关键资源的数量。 (2)关键路径长度。 (3)关键字节的数量。

阻塞渲染的情况

  1. 多层级的dom树和css树
  2. 放在头部的js

浏览器本地存储

cookie

每个cookie大小不超过4kb,数量不能超过20个; 每次请求都会被携带

缺点:安全性

LocalStorage

特性:大小5MB,不会被清除,请求不会携带

缺点:1. IE8 下不支持;2. 隐私模式的浏览器无法读取; 3. 非同源页面 访问不到

SessionStorage

特性:大小5MB,请求不会携带,关闭标签页会被清除

IndexedDB

特性:内存大 250MB;同源策略;支持失败即回滚;异步,上面都是同步的;对象仓库,所有key都是唯一的;支持二进制存储

浏览器同源策略

同源策略

同源指的是:协议、端口号、域名必须一致。

不能跨域请求、不能获取缓存、不能操作dom

如何解决

  1. cors:浏览器服务器同时支持,
    1. 简单请求中解决跨域(简单请求:请求方式为HEAD、GET、POST之一;HTTP头信息只有Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type的几个)

      1. 在简单请求中,在服务器内,至少需要设置字段:Access-Control-Allow-Origin
    2. 非简单请求

      1. 先发送预检请求;请求通过解决跨域
        1. 预检请求时OPTIONS,头部信息带origin(必须)、Access-Control-Request-Method(必须)、Access-Control-Request-Headers
        2. 服务要设置的字段 'Access-Control-Allow-Origin' 'Access-Control-Allow-Methods' 'Access-Control-Allow-Headers'
      2. 减少OPTIONS的请求次数可以通过设置Access-Control-Max-Age(缓存时间);可以提高网页性能。
    3. CORS中Cookie相关问题:

      1. 跨域请求携带cookie 需要在请求中设置 withCredentials
  2. JSONP
    1. jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
    2. 缺点:
      1. 具有局限性, 仅支持get方法
      2. 不安全,可能会遭受XSS攻击
  3. postMessage跨域
    1. 解决场景
      1. 页面和其打开的新窗口的数据传递
      2. 多窗口之间消息传递
      3. 页面与嵌套的iframe消息传递
      4. 上面三个场景的跨域数据传递
    2. postMessage(data,origin)
  4. nginx代理跨域:
    1. 通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。
  # proxy服务器
  server {
    listen 81;
    server_name www.domain1.com;
    location / {
      proxy_pass http://www.domain2.com:8080; #反向代理
      proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
      index index.html index.htm;
      # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
      add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
      add_header Access-Control-Allow-Credentials true;
    }
  }
  1. nodejs 中间件代理跨域

node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

  1. document.domain + iframe跨域:此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
  2. location.hash + iframe跨域:
  3. window.name + iframe跨域
  4. WebSocket协议跨域

正向代理、反向代理

正向代理:客户端做代理,为隐藏客户端

反向代理:服务端做代理,为隐藏服务端ip

4. Nginx的概念及其工作原理

轻量级web服务器

浏览器事件机制

事件及事件模型

事件:交互事件

事件模型

  1. DOM 0级事件:直接在dom对象上注册事件名称,就是DOM0写法。
  2. IE事件模型:两个阶段,先处理、后冒泡(从下往上)
  3. DOM 2级事件:三个阶段,先捕获(从上往下)找到目标元素,期间有事件就执行;到了目标元素就事件处理,然后冒泡

阻止冒泡: 普通浏览器使用:event.stopPropagation() IE浏览器使用:event.cancelBubble = true;

事件委托

概念:点击事件的冒泡机制,将事件委托到某个父节点上,父节点来执行方法;如列表

特点:减少内存消耗,动态绑定事件

局限性:focus、blur没有冒泡机制因此事件委托;mouseout、对性能消耗高

使用场景

同步事件、异步事件

  1. 同步:同步方法执行时,会阻塞
  2. 异步:不阻塞后续操作

事件循环

js是单线程,在执行同步代码时,遇到异步代码,执行后不会等待返回,js会继续执行下一个任务,异步任务执行完毕后,会放到任务队列中等待执行。任务队列分微任务和宏任务,当当前执行栈中的任务执行完后, 会先将剩余的微任务压栈执行,然后是宏任务。

Event Loop 执行顺序如下所示:

  • 首先执行同步代码,这属于宏任务
  • 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
  • 执行所有微任务
  • 当执行完所有微任务后,如有必要会渲染页面
  • 然后开始下一轮 Event Loop,执行宏任务中的异步代码

宏任务、微任务

  • 宏任务:定时器事件、script执行,UI渲染,I/O操作
  • 微任务:promise、node的process.nextTick、MutationObserver

执行栈

可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。 当开始执行 JS 代码时,根据先进后出的原则,后执行的函数会先弹出栈,

栈有限制,放多了会爆栈

Node 中的 Event Loop 和浏览器中的有什么区别?process.nextTick 执行顺序?

事件触发的过程是怎样的

  1. 捕获,处理,冒泡 同时注册,会顺序执行
  2. stopPropagation,可以阻止向上冒泡、向下捕获
  3. stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。

浏览器垃圾回收机制

  1. 新生代:两个空间,From,to。From内存用完了,将活得放到to,删掉from再换回来
  2. 老生代:
    1. 会出现的原因:用过新生代算法的、To的大小超过25%
    2. 标记清除法(过滤一些):某一空间没分块、空间被对象超过一定限制、空间不能保证新生代移到老生代;清除后会有碎片,将碎片压缩后,将可用的向另一端移动,清理掉不要的内存

内存泄露

  1. 无法回收的变量
  2. 一直被引用的变量。比如setInterval内部使用的外部变量
  3. DOM元素的引用
  4. 不合理的使用闭包,从而导致某些变量一直被留在内存当中