浏览器

TIP

最后更新时间:2019年9月10

字数:44457

努力不一定成功,但放弃一定失败!加油

学习资料

C/S架构

Client/Server(客户机/服务器)结构

介绍

  • C/S是大家熟知的软件系统体系结构,通过将任务合理分配到Client端(客户端)和Server端(服务端),降低了系统的通讯开销,需要安装客户端才可进行管理操作。
  • 客户端和服务器端的程序不同,用户的程序主要在客户端,服务器端主要提供数据管理、数据共享、数据及系统维护和并发控制等
  • 客户端程序主要完成用户的具体的业务。
  • 优缺点:开发比较容易,操作简便,但应用程序的升级和客户端程序的维护较为困难。

实际场景

  • 常见大型游戏,QQ,微信等都是C/S架构

B/S架构

Browser/Server(浏览器/服务器)结构,前端开发基本都是C/S架构

介绍

  • 只安装维护一个服务器(Server),而客户端采用浏览器(Browse)运行软件
  • B/S结构的主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。
  • 但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,这些缺点是有目共睹的,难以实现传统模式下的特殊功能要求。
  • 例如通过浏览器进行大量的数据输入或进行报表的应答、专用性打印输出都比较困难和不便。
  • 此外,实现复杂的应用构造有较大的困难。

实际场景

  • 所有用浏览器实现的架构都是B/S架构

C/S VS B/S

可维护性

  • C/S每一个客户端都要升级程序。就类似我们升级软件一样
  • 可以采用自动升级,BS客户端不必安装及维护,服务器升级即可

硬件环境

  • C/S用户固定,并且处于相同区域,要求拥有相同的操作系统。
  • B/S要有操作系统和浏览器就行,与操作系统平台无关。

软件安装

  • C/S每一个客户端都必须安装和配置软件。
  • B/S客户端不必安装,使用浏览器访问,易推广。
  • B/S最大的优点就是可以在任何地方进行操作而不用安装任何专门的软件。

客户端要求

  • C/S客户端的计算机电脑配置要求较高。
  • B/S客户端的计算机电脑配置要求较低。

安全性

  • C/S一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。一般高度机密的信息系统采用C/S结构适宜。

浏览器

  • 网页浏览器:(web browser),也被称作浏览器,是通过URL来获取并显示Web网页的一种软件工具。
  • 专业说法:
    • 浏览器是一种用于检索并展示万维网信息资源的应用程序。
    • 这些信息资源可为网页、图片、影音或其他内容,它们由统一资源标志符标志。
    • 信息资源中的超链接可使用户方便地浏览相关信息。

常见浏览器

  • Mozilla Firefox、
    • 火狐浏览器
  • Internet Explorer
    • 微软的IE浏览器
  • Microsoft Edge
    • 微软最新浏览器,取代ie
  • Google Chrome
    • 谷歌浏览器
  • Opera
    • 欧朋浏览器
  • Safari
    • 苹果的iOS和macOS自带浏览器
  • 国产浏览器
    • QQ浏览器
    • 360浏览器
      • 360安全浏览器
      • 360急速浏览器
    • UC浏览器
    • 搜狗高速浏览器
    • 2345加速浏览器
    • 百度浏览器

浏览器内核

  • 浏览器内核,经常被称为排版引擎(layout engine)渲染引擎(rendering engine)
  • 浏览器内核负责对网页语法的解释(如标准通用标记语言下的一个应用HTML、JavaScript)并渲染(显示)网页。
  • 不同的浏览器在获取到某页面的代码文件后,负责根据这套规范将代码渲染出来呈现给用户,浏览器内核所做的就是这个渲染工作。
  • 由于不同的浏览器内核对网页编写语法的解释有不同,因此同一网页在不同的内核的浏览器里的渲染(显示)效果也可能不同,这也是网页编写者需要在不同内核的浏览器中测试网页显示效果的原因。

TIP

前端开发人员很痛恨的一个吐槽点:浏览器兼容问题,就是浏览器内核的锅

常见浏览器内核

  • Trident(IE内核)
  • Gecko(Firefox内核)
  • Presto(Opera前内核) (已废弃)
    • Opera现已改用Google Chrome的Blink内核
  • Webkit(Safari内核,Chrome内核原型,开源)
  • Blink

Trident(IE内核)

  • 997年的IE4中首次被采用,是微软在Mosaic代码的基础之上修改而来的,并沿用到IE11
  • 内核程序在1997年的IE4中首次被采用,是微软在Mosaic代码的基础之上修改而来的,并沿用到IE11,也被普遍称作”IE内核”。
  • 从ie 9(2011)开始,Trident开始支持HTML5和CSS 3,所以我们经常会看到有些网站在浏览时会提示用户(在Internet Explorer 9.0+以上浏览效果最佳)
  • 国内大部分浏览器初期都是以Trident内核为基础,后期发布的双核或者多核浏览器,其中一个内核基本都是Trident内核,另一个内核可以选择其他

TIP

国内的厂商一般把其他内核叫做“高速浏览模式”,而Trident则是“兼容浏览模式”,用户可以来回切换

Gecko(Firefox内核)

  • 代码完全公开
  • Netscape6开始采用的内核,后来的Mozilla FireFox(火狐浏览器)也采用了该内核
  • 由来(IE的锅):
    • IE由于windows的原因处于垄断地位,长时间不开发新版本(吃老本),导致了微软内部一些开发人员的不满
    • 他们与当时已经停止更新了的 Netscape的一些员工一起创办了Mozilla,以当时的Mosaic内核为基础重新编写内核,于是开发出了Gecko。
    • 不过事实上,Gecko 内核的浏览器仍然还是Firefox (火狐浏览器)用户最多,所以有时也会被称为Firefox内核。
    • 此外Gecko也是一个跨平台内核,可以在Windows、 BSD、Linux和Mac OS X中使用。

TIP

Trident和Gecko 内核的开发,都和IE有直接关系

Presto(Opera前内核)

  • Presto是一款商业引擎,收费的那种,所以也一定程度上阻碍了它的发展

  • Opera浏览器前内核,现在已经不再使用了,Opera现已改用Google Chrome的Blink内核

  • 该款引擎的特点就是渲染速度的优化达到了极致,代价是牺牲了网页的兼容性

  • Presto动态内核,在处理JavaScript的时候,速度非常快,同等条件下Trident和Gecko内核的约1/3,(Trident内核最慢)

Webkit(Safari内核,Chrome内核原型,开源)

  • 这是苹果公司开发的内核,也是其旗下产品Ssfari浏览器使用的内核。
  • Webkit引擎包含了WebCode排版引擎和JavaScriptCode解析引擎,分别是从KDE的KHTML和KJS衍生而来,它们都是自由软件,在GPL条约下授权,同时支持BSD系统开发。
  • Google Chrome、360极速浏览器以及搜狗高速浏览器高速模式也使用Webkit作为内核(在脚本理解方面,Chrome使用自己研发的V8引擎)。
  • WebKit 内核在手机上的应用也十分广泛,例如 Google 的手机 Gphone、 Apple 的iPhone, Nokia’s Series 60 browser 等所使用的 Browser 内核引擎,都是基于 WebKit。

TIP

  • 移动设备iPhone和iPad等苹果iOS平台上面safari浏览器内核是webkit
  • Android 4.4之前的Android系统浏览器内核是WebKit
  • Android4.4系统浏览器切换到了Chromium,内核是Webkit的分支Blink
  • 市场上主流移动端浏览器内核都是webkit或者和webkit关系很大
  • Blink是一个由Google和OperaSoftware开发的浏览器渲染引擎,Google将这个渲染引擎作为Chromium计划的一部分。
  • 2013年4月,Google宣布将为Chrome浏览器开发新的自主渲染引擎Blink,与WebKit分道扬镳
  • 由来:
    • 早起搭载iOS和Android系统智能手机称霸全球手机市场,苹果和Google推动WebKit使其成为目前最大的浏览器引擎。
    • 但是由于苹果在这个开源系统中有更多的话语权,Google只能被动接受,话语权不行,Google受制于人
    • 浏览器对Google的重要性远胜于苹果,在自己的核心领域绝不能受制于人,因此Google决定利用WebKit的成果,开发自己的Blink引擎。

Chromium

  • Chromium是一个由Google主导开发的网页浏览器,以BSD许可证等多重自由版权发行并开放源代码。
  • 特点:
    • 设计思想基于简单、高速、稳定、安全等理念
    • 在架构上使用了Apple发展出来的WebKit排版引擎、Safari的部份源代码与Firefox的成果
    • 并采用Google独家开发出的V8引擎以提升解译JavaScript的效率
    • 而且设计了“沙盒”、“黑名单”、“无痕浏览”等功能来实现稳定与安全的网页浏览环境。
  • 区别:
    • Chromium是Google为发展自家的浏览器Google Chrome(以下简称Chrome)而开启的计划
    • 所以Chromium相当于Chrome的工程版或称实验版(尽管Chrome自身也有β版阶段)
    • 新功能会率先在Chromium上实现,待验证后才会应用在Chrome上
    • 故Chrome的功能会相对落后但较稳定。
  • 更新:
    • Chromium的更新速度很快,每隔数小时即有新的开发版本发布,而且可以免安装
    • 下载zip封装版后解压缩即可使用(Windows下也有安装版)
    • Chrome虽然理论上也可以免安装,但Google仅提供安装版。

Chromium vs Google chrome

  • Chromium

    • 是 Google 的chrome浏览器背后的引擎,其目的是为了创建一个安全、稳定和快速的通用浏览器。
    • 国内的大部分双核浏览器都采用Chromium内核。
  • Google Chrome,

    • 又称Google浏览器
    • 是一个由Google(谷歌)公司开发的网页浏览器。
    • 该浏览器是基于其他开源软件所撰写,包括WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。
  • 两者之间的差异:

    • Chromium是谷歌的开源项目,开发者们可以共同去改进它,然后谷歌会收集改进后的Chromium并发布改进后安装包,Chrome不是开源项目,谷歌会把Chromium的东西更新到Chrome中。
    • Chromium不用安装,下载下来的是压缩包,解压后直接就可以使用,Chrome需要安装;
    • Chromium功能比Chrome多,因为新功能都是先在Chromium中使用,等完善后才添加到Chrome中,相对的Chrome就要比Chromium稳定很多不容易出错;
    • Chromium不开放自动更新功能,所以用户需手动下载更新,而Chrome则可自动连上Google的服务器更新,但新版的推出很慢

::tip

可以理解为Chromium是体验版,Chrome是正式版

:::

V8引擎

  • V8引擎是一个JavaScript引擎实现,后被谷歌收购,随后进行了开源。
  • V8使用C++开发,在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能。
  • 有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序。V8支持众多操作系统,如windows、linux、android等,也支持其他硬件架构,如IA32,X64,ARM等,具有很好的可移植和跨平台特性。

JavaScript引擎

  • JavaScript引擎是执行JavaScript代码的程序或解释器。
  • javaScript引擎可以实现为标准解释器或即时编译器,它以某种形式将JavaScript编译为字节码。

TIP

  • v8会把js代码转换为高效的机器码,而不在是依赖于解释器去执行

  • v8引入了JIT在运行时把js代码进行转换为机器码

浏览器区分

在许多情况下,值判断出浏览器类型之后,还需判断浏览器版本才能处理兼容性问题,而判断浏览器的版本一般只能通过分析浏览器的userAgent才能知道

userAgent

  • userAgent 属性是一个只读的字符串,声明了浏览器用于 HTTP 请求的用户代理头的值
  • 一般来讲,它是在 navigator.appCodeName 的值之后加上斜线和 navigator.appVersion 的值构成的
  • 访问:navigator.userAgent

判断浏览器类型

// 判断打开的浏览器 电脑版本的safari不支持
var Navigator = navigator.userAgent;

var Chrome = Navigator.match(/Chrome/i) != null && Navigator.match(/Version\/\d+\.\d+(\.\d+)?\sChrome\//i) == null ? true : false;

var Android = (Navigator.match(/(Android);?[\s\/]+([\d.]+)?/)) ? true : false;

var iPad = (Navigator.match(/(iPad).*OS\s([\d_]+)/)) ? true : false;

var iPhone = (!iPad && Navigator.match(/(iPhone\sOS)\s([\d_]+)/)) ? true : false;

var Safari = (iPhone || iPad) && Navigator.match(/Safari/);

var version = 0;
Safari && (version = Navigator.match(/Version\/([\d\.]+)/));
// safari浏览器版本
version = parseFloat(version[1], 10);

// 是否从微信打开
var Weixin = navigator.userAgent.indexOf("MicroMessenger") >= 0; // weixin

// 使用
if(Android) {
    if(weixin) {
        // 微信浏览器
    } else {
        // 非微信浏览器
	}
}
if(iPhone) {
    if(weixin) {
        // 微信中
    } else {
		// 不是微信中        
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

TIP

  • 这里要判断微信的原因:
    • 微信中打开App是有限制的,但是我们经常做的功能可能就是浏览器打开App
    • 这个时候在微信中是无法打开的,所以需要判断,在微信中一般提示用户打开浏览器,通过浏览器再打开App
    • 如果不是微信中,直接打开App即可

判断浏览器版本

参考文章:JavaScript判断浏览器类型及版本

var Sys = {};
var ua = navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
(s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
(s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
(s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
(s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;

//以下进行测试
if (Sys.ie) document.write('IE: ' + Sys.ie);
if (Sys.firefox) document.write('Firefox: ' + Sys.firefox);
if (Sys.chrome) document.write('Chrome: ' + Sys.chrome);
if (Sys.opera) document.write('Opera: ' + Sys.opera);
if (Sys.safari) document.write('Safari: ' + Sys.safari);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 效果图(chrome,火狐,safari测试通过)

浏览器插件

浏览器的组成

我们常见的浏览器由一下几大部分组成:

用户界面( User Interface )

介绍

  • 用户操作界面,包含收藏夹、工具栏,各种功能按钮
  • 也就是我们看到的除了加载的网页部分的界面都是用户界面

功能介绍

  • 提供了我们与浏览器的功能交互
  • 我们操作浏览器大部分都是操作和这些界面打交道

TIP

用户界面使我们对浏览器最直观认识的界面,大部分都是可以看到和操作的

浏览器引擎( Browser engine )

介绍

  • 用来查询及操作渲染引擎的接口
  • 在用户界面和渲染引擎之间传达指令

功能介绍

  • 比如我们点击刷新,浏览器引擎就会把用户界面的刷新指令,传递给渲染引擎,渲染引擎会重新渲染页面

渲染引擎( Rendering engine )

介绍

  • 重点需要掌握的部分

  • 渲染引擎的职责就是渲染

  • 用来显示我们请求回来的数据

  • 一般情况下我们请求的网页都是他来显示的,它负责解析html和css,然后显示出来

功能介绍

  • 渲染引擎可以显示html、xml文档及图片,(借助第三方还可以显示其他格式的数据)
  • 加载我们请求回来的网页
  • 响应浏览器引擎的用户操作指令,渲染和显示网页

TIP

渲染引擎又称为排版引起或者浏览器内核,本章上一部分包含了许多浏览器内核介绍

常见浏览器内核

网络模块( Networking )

介绍

  • 用来完成网络调用

功能介绍

  • 用来发送网络请求
  • 比如我们的ajax和xhr请求

UI 后端( UI Backend )

  • 用来绘制类似组合选择框及对话框等基本组件
  • 具有不特定于某个平台的通用接口
  • 底层使用操作系统的用户接口

JS解释器( JavaScript Interpreter )

数据存储( Data Persistence )

介绍

  • 用于数据持久化
  • 浏览器需要在本地硬盘中保存类似cookie的各种数据

功能介绍

  • HTML5定义了web database技术,这是一种轻量级完整的客户端存储技术
  • 我们常用的缓存就是:Cookie以及HTML5中的本地存储 LocalStorage、SessionStorage)

常见数据存储方式

  • cookie数据始终在同源的http请求中携带(即使不需要)
  • cookie在浏览器和服务器间来回传递
  • 大小不超过4k
  • cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下
  • cookie也是在所有同源窗口中都是共享的

LocalStorage

  • 保存数据最大可以达到5M,甚至更多
  • 数据保存在本地磁盘(保存对象:JSON.stringfy()和JSON.parse())
  • 数据始终有效,窗口或浏览器关闭也一直保存
  • localStorage 在所有同源窗口中都是共享的

SessionStorage

  • 保存数据最大可以达到5M,甚至更多
  • 浏览器窗口(重点)
    • sessionStorage是在同源的同窗口(或tab)中,始终存在的数据。
    • 仅在当前浏览器窗口关闭前有效
    • 只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在。
    • 关闭窗口后,sessionStorage即被销毁。
    • 同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的。
    • sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面

TIP

数据持久化,需要注意数据保存的方式,保存的时间以及数据的清除工作

sessionStorage 、localStorage 和 cookie 三者都是保存在浏览器端,且同源的

跨域

什么是跨域

跨域是浏览器行为,是浏览器安全方面的考虑,是浏览器基于同源策略做出的限制

TIP

后端开发中是没有跨域限制的,因为跨域是浏览器行为,有时候有些后台开发不懂后台配置跨域,就会甩锅给前端,其实前端开发解决起来并没有那么简单,很多时候还是需要后台配合的

不允许跨域访问并非是浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了 最好的例子是CSRF跨站攻击原理,请求是发送到了后端服务器,无论是否设置允许跨域

有些浏览器不允许从HTTPS跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是特例

URL

  • URL全程统一资源定位符,是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
  • 互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

基础组成

模式(或称协议)、服务器名称(或IP地址,这其中包含端口)、路径和文件名

同源策略(SOP)

  • 简单说来,要求协议,域名,端口都相同才可以,否则均认为需要做跨域的处理

协议相同

  • 同源策略要求协议必须一致
  • 常见协议
    • HTTP:超文本传输协议
    • HTTPS:(全称:Hypertext Transfer Protocol over Secure Socket Layer),简单讲是HTTP的安全版
    • FTP:File Transfer Protocol文件传输协议
    • TCP:传输协议,HTTP是应用协议
    • mailto:电子邮件地址
    • ldap:轻型目录访问协议搜索
    • file:当地电脑或网上分享的文件
    • news:Usenet新闻组
    • gopher:Gopher协议
    • telnet:Telnet协议

TIP

同源策略要求协议相同,不同协议就是跨域

域名相同

  • 相同域名,要求主域名和子域名都相同
  • 相同域名,要求主域名和二级域名都相同

端口相同

  • 端口号一般都是默认的

TIP

端口和协议的不同,只能通过后台来解决

localhost和127.0.0.1虽然都指向本机,但也属于跨域

造成跨域的两种策略

DOM同源策略

  • 浏览器会禁止对不同源页面DOM进行操作。
  • 主要针对场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。

出现场景

  • 如果没有这个限制,我们做一个假的网站(a.com),内嵌一个iframe(指向银行网站(b.com))
  • 把iframe做成银行网站的样子,用户有时候是看不出来的
  • 这时如果用户输入账号密码,我们的主网站(假网站(a.com))可以跨域访问到指向银行网站(b.com)iframe的DOM节点,就可以拿到用户的账户密码了

XHR同源策略

  • XMLHttpRequest可以发送ajax
  • 浏览器禁止使用XHR对象向不同源的服务器地址发起HTTP请求

出现场景

  • 用户登录了自己的银行页面(a.com),(a.com) 向用户的 cookie 中添加用户标识。
  • 用户浏览了恶意页面(b.com),执行了页面中的恶意 AJAX 请求代码。
  • 恶意页面(b.com) 向(a.com)发起 AJAX HTTP 请求,请求会默认把(a.com)对应 cookie 也同时发送过去。
  • 银行页面从发送的 cookie 中提取用户标识,验证用户无误,response 中返回请求数据。此时数据就泄露了。

TIP

综上所述,浏览器处于安全方面的考虑,要禁止跨域访问

跨域解决方案

支持跨域的标签

html中有许多标签是支持跨域的:

  • img、script、css、video、audio、object、embed、applet、@font-face、frame、iframe

注意事项

  • <link src="">标签嵌入CSS
    • 由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头
    • 不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera
  • @font-face引入的字体
    • 一些浏览器允许跨域字体( cross-origin fonts)
    • 一些需要同源字体(same-origin fonts)
  • <frame> 和 <iframe>载入的任何资源
    • 站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。

跨域资源共享(CORS)

既然存在跨域问题,那么我们怎么解决这个问题呢?

  • W3C提出了一个标准,那就是CORS(跨域资源共享:Cross-origin resource sharing)
  • CORS需要浏览器和服务器同时支持
  • 如果设置了CORS,那么浏览器就会允许我们发送的ajax突破同源策略,向不同的服务器发送请求

TIP

目前,所有浏览器都支持CORS功能

CORS分类

  • 简单请求
  • 非简单请求

TIP

浏览器对两种请求的处理是不一样的!不一样啊不一样!

简单请求

  • 简单请求请求方法只有三种:

    • HEAD
    • GET
    • POST
  • 简单请求的请求头不超出以下字段

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type只限于三个值:
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

TIP

凡是不同时满足上面两个条件,就属于非简单请求

非简单请求(预检请求)

  • 除了简单请求以外的CORS请求

  • 非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是 application/json

  • 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)

    • 浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。
    • 只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错
    • "预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。
    • 头信息里面,关键字段是Origin,表示请求来自哪个源
  • 预检请求包含字段:

    • Origin:表示请求来自哪个源

    • Access-Control-Request-Method

      • 必须的
      • 用来列出浏览器的CORS请求会用到哪些HTTP方法
    • Access-Control-Request-Headers:

      • 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
    • Access-Control-Allow-Methods:

      • 必须
      • 它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。
      • 注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
    • Access-Control-Allow-Headers

      • 如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。
      • 它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
    • Access-Control-Max-Age

      • 可选
      • 用来指定本次预检请求的有效期,单位为秒。
HTTP/1.1 200 OK
Date: Fri, 9 Nov 2018 09:29:26 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: https://api.xuefeng666.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
1
2
3
4
5
6
7
8
9
10
11
12

TIP

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求.

就都跟简单请求一样,会有一个Origin头信息字段。

服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段

CORS后台配置示例(NodeJs)

let app = express()
app.all('*',(req,res,next)=>{
    // 消除中文乱码
    res.set('Content-Type','application/json;charset=utf-8');

    //设置跨域访问CORS
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By",' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
})
1
2
3
4
5
6
7
8
9
10
11
12
13

TIP

如果要发送Cookie,Access-Control-Allow-Origin就不能设为通配符*

必须指定明确的,与请求网页一致的域名

并且Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传

其他域名的Cookie并不会上传,且原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

JSONP

JSONP:JSON with Padding

HTML脚本元素是可以规避SOP检查的,我们可以利用这个,采用动态注入脚本的方式来解决跨域问题

基本思路

  • 网页通过添加一个<script>元素,向服务器请求JSON数据
  • 这种做法不受同源政策限制
  • 服务器收到请求后,将数据放在一个指定名字的回调函数里传回来

实现步骤

  • 首先前端先设置好回调函数,并将其作为 url 的参数。
  • 服务端接收到请求后,通过该参数获得回调函数名,并将数据放在参数中将其返回
  • 收到结果后因为是 script 标签,所以浏览器会当做是脚本进行运行,从而达到跨域获取数据的目的

后端实现逻辑(Nodejs)

//server.js
const url = require('url');
	
require('http').createServer((req, res) => {

    const data = {
		name: 'xiaofengge'
    };
    // url.parse:解析一个 URL 字符串并返回一个 URL 对象
    // query.callback:获得callback对应的方法名
    const callback = url.parse(req.url, true).query.callback;
    res.writeHead(200);
    // 返回一个函数的调用
    // 这里是:jsonpCallback({name:"xiaofengge"})
    // jsonpCallback是获取到的前端传递的方法名
    res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, '127.0.0.1');

console.log('启动服务,监听 127.0.0.1:3000');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

前端逻辑实现(html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp模拟</title>
</head>
<body>
    <script>
	function jsonpCallback(data) {
	    alert('获得 name 是:' + data.name);
	}
    </script>
    <script src="http://127.0.0.1:3000?callback=jsonpCallback"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

TIP

后端返回的是 jsonpCallback({name:"xiaofengge"})

等同于<script>jsonpCallback({name:"xiaofengge"})</script>

JSONP优点

  • 它不像XMLHttpRequest 对象实现 Ajax 请求那样受到同源策略的限制
  • 它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
  • 在请求完毕后可以通过调用 callback 的方式回传结果,将回调方法的权限给了调用方

JSONP缺点(局限性)

  • 它支持 GET 请求而不支持 POST 等其它类行的 HTTP 请求

    • 意味着GET请求的诸多限制JSONP也有
  • 它只支持跨域 HTTP 请求这种情况

  • jsonp在调用失败的时候不会返回各种HTTP状态码

    • 如果脚本注入成功后,就会调用回调函数,但是注入失败后,没有任何提示
    • 这就意味着,当JSONP遇到404、505或者其他服务器错误时,你是无法检测出错原因的
    • 我们能够做的也只有超时,没有收到响应,便认为请求失败,执行对应的错误回调
  • 借助JSONP有可能进行跨站请求伪造(CSRF)攻击

TIP

当一个恶意网站使用访问者的浏览器向服务器发送请求并进行数据变更时,被称为CSRF攻击。

由于请求会携带cookie信息,服务器会认为是用户自己想要提交表单或者发送请求,而得到用户的一些隐私数据

jQuery中JSONP跨域

  • jquery 会在window对象中加载一个全局的函数
  • 动态添加<script>标签,当 <script>代码插入时函数执行
  • 执行完毕后就<script>会被移除
// 原始请求地址
http://192.168.1.1/test.php

// jQuery会自动转化为
<script type="text/javascript"src="http://192.168.1.1/test.php?backfunc= jQuery2030038573939353227615_1402643146875&参数1=值1"></script>
1
2
3
4
5

TIP

如果不添加dataType:jsonp,jquery底层默认发送XMLHttpRequest请求

Ajax缓存

Ajax在发送的数据成功后,会把请求的URL和返回的响应结果保存在缓存内

当下一次调用Ajax发送相同的请求时,它会直接从缓存中把数据取出来,这是为了提高页面的响应速度和用户体验

当前这要求两次请求URL完全相同,包括参数,这个时候,浏览器就不会与服务器交互

缓存解决方案

  • 在ajax发送请求前加上 xmlHttpRequest.setRequestHeader(“Cache-Control”,”no-cache”)
  • 在服务端加 header(“Cache-Control: no-cache, must-revalidate”)
  • 在ajax发送请求前加上 xmlHttpRequest.setRequestHeader(“If-Modified-Since”,”0″)
  • 在 Ajax 的 URL 参数后加上 "?fresh=" + Math.random(); //参数 fresh 可以任意取了
  • 第五种方法和第四种类似,在 URL 参数后加上 "?timestamp=" + new Date().getTime()
  • 用POST替代GET:不推荐

TIP

jQuery 中 ajax 许多都是采用url后面添加随机数的形式,这样url和参数改变了,浏览器就不会缓存了

服务器代理(Server Proxy)

跨域是因为浏览器的限制,在服务端是不存在跨域的

原理

服务器代理,顾名思义,当你需要有跨域的请求操作时发送请求给后端,让后端帮你代为请求,然后最后将获取的结果发送给你

后端逻辑实现(NodeJs)

const url = require('url');
const http = require('http');
const https = require('https');
// 我们请求的是http://www.xuefeng666.com/api/newsList
const server = http.createServer((req, res) => {
    const path = url.parse(req.url).path.slice(1);
    if(path === 'newsList') { 
    // 服务器去另一个域名帮我们请求数据,进行转发
	https.get('http://www.xuefeng66.com/api/newsList', (resp) => {
	    let data = "";
	    resp.on('data', chunk => {
		data += chunk;
	    });
	    resp.on('end', () => {
		res.writeHead(200, {
		    'Content-Type': 'application/json; charset=utf-8'
		});
        // 将代为请求的数据返回给我们
		res.end(data);
	    });
	})		
    }
}).listen(3000, '127.0.0.1');

console.log('启动服务,监听 127.0.0.1:3000');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

webpack配置代理

proxyTable: {  
    '/api': {  //代理地址  
        target: 'http://1.1.1.1:8000/',  //需要代理的地址  
        changeOrigin: true,  //是否跨域  
        secure: false,    
        pathRewrite: {  
            '^/api': '/' //本身的接口地址没有 '/api' 这种通用前缀,所以要rewrite,如果本身有则去掉  
        }
    }
}

// 发送请求
// 请求数据时URL前加上“/api”就可以跨域请求了
this.$axios.get('/api/queryRole', {params: params})  
    .then((res) => {  
        console.log(res);  
    }).catch((err) => {  
        console.log(err);  
    })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

TIP

webpack配置代理只是开发环境可以使用,线上环境一般是nginx配置代理,或者是服务器代码中添加api转发之类的功能

postMessage()

postMessage是html5引入的API可以更方便、有效、安全的解决这些问题

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递

postMessage()可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage

该方法可以通过绑定window的message事件来监听发送跨文档消息传输内容

postMessage原理

  • window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent消息
  • 该MessageEvent消息有四个属性需要注意:
  • data:
    • 从其他 window 中传递过来的数据
  • origin :
    • 调用 postMessage 时消息发送方窗口的 origin . 这个字符串由 协议、“😕/“、域名、“ : 端口号”拼接而成
  • source :
    • 记录调用 window.postMessage() 方法的窗口信息
    • 对发送消息的窗口对象的引用

示例代码

a.html

<!-- 输入数据,点击发送post message -->
<input type="text" id="data">
<button style="font-size:20px;" onclick="send()">post message</button>

<!-- 添加一个iframe -->
<iframe src="http://127.0.0.1:8081/b.html" style="display: none"></iframe>

<script>
    function send() {
        // 获取输入的数据
        var data = document.querySelector('#data').value;

        // 其他窗口的一个引用
        // 1.比如iframe的contentWindow属性
        // 2.执行window.open返回的窗口对象
        // 3. 命名过或数值索引的window.frames
        // 注意:不能使当前页面window去掉用
        window.frames[0].postMessage(data, 'http://127.0.0.1:9022'); // 触发跨域子页面的messag事件
    }
    window.addEventListener('message', function(e) {
        console.log('a.html 接收到的消息:', e.data);
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

b.html

<script>
    // b 页面监听message事件,获取数据后,返回数据
    window.addEventListener('message', function(ev) {
        var data = ev.data;
        console.info('服务器接收到的a.html的消息是:', data);
		// 这里的parent: window.parent:返回当前窗口的父窗口
        parent.postMessage('我已经接收到消息了!,服务器返回信息是:123',ev.origin);

    }, false);

</script>
1
2
3
4
5
6
7
8
9
10
11

语法

otherWindow.postMessage(message, targetOrigin, [transfer]);
1

otherWindow

  • 其他窗口的一个引用
    • 比如iframe的contentWindow属性
    • 执行 window.open 创建返回的窗口对象
    • 命名过或数值索引的 window.frames [0]

message

  • 将要发送到其他 window的数据

TIP

html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果 (来源 MDN)

targetOrigin

  • 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI
  • 在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口

TIP

开发安全规范:

如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。

不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点

transfer

  • 可选参数

window.name

我们可以利用全局变量window的name属性进行跨域

window.name特点

  • 每个窗口都有独立的window.name与之对应
  • 在一个窗口的生命周期中(被关闭前),窗口载入的所有页面同时共享一个window.name,每个页面对window.name都有读写的权限
  • window.name一直存在与当前窗口,即使是有新的页面载入也不会改变window.name的值;
  • window.name可以存储不超过2M的数据,数据格式按需自定义

跨域步骤

  • 就是在a.html页面中使用一个隐藏的iframe来充当一个中间角色,由iframe去获取b.html的数据

  • 然后把这个iframe的src设置为www.xuefeng666.com/b.html

  • 接着a.html再去得到iframe获取到的数据

TIP

iframe的src设置成跟a.html页面同一个域才行,不然根据同源策略,a.html是不能访问到iframe中的window.name属性的

封装代码

<script type="text/javascript">
	//这里之所以要设置flag,是因为每当改变location的时候,就会重新来一次onload,所以我们希望获取到数据之后,就直接close()
    var flag = false;
    var iframe = document.createElement('iframe');
    var loadDataFn = function() {
        if (flag) {
            // 获取数据,也就是获取window.name
            var data = iframe.contentWindow.name;
            console.log(data); 
            
            //销毁数据   
            iframe.contentWindow.document.write('');
            iframe.contentWindow.close();
            document.body.removeChild(iframe);
            
        } else {
            // 第一次进入这里,修改b.html,触发onload,再次调用loadDataFn方法
            flag = true;
            iframe.contentWindow.location = "b.html";    // 设置的代理文件,iframe重新载入
        }  
    };
	// 设置iframe的src指向另外一个url
    iframe.src = 'http://www.xuefeng666.com/test.html';
	
	// 添加onload事件的兼容写法
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadDataFn);
    } else {
        iframe.onload  = loadDataFn;
    }
	// 添加iframe
    document.body.appendChild(iframe);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

location.hash

url:xxx.com#app的 "#app" 就是 location.hash

改变 hash 值不会导致页面刷新,所以可以利用 hash 值来进行数据的传递,当然数据量是有限的

TIP

和我们Vue项目中经常讲的路由差不多

document.domain

具有相同document.domain的页面,就相当于是处在同域名的服务器上,如果协议和端口号也是一致,那它们之间就可以跨域访问数据

flash

网传flash有跨域解决方案,大家可以自行百度一下!!!

判断浏览器是不是第一次打开

在刷新的时候,不但window不会被销毁,自定义在window对象上的属性也会被保留。那么我们就可以利用这个特性记录一些信息了

<script>
    if(window.name === "firstInIndex") {
        alert("页面刷新"+window.name)
    }else {
        alert("第一次打开"+window.name)
        window.name = "firstInIndex"
    }
</script>
1
2
3
4
5
6
7
8

浏览器插件

浏览器渲染过程

浏览器兼容

cookie和session

原理

  • cookie采用的是客户端的会话状态的一种储存机制,它是服务器在本地机器上存储的小段文本或者是内存中的一段数据,并随每一个请求发送至同一个服务器
  • session是一种服务器端的信息管理机制,它把这些文件信息以文件的形式存放在服务器的硬盘空间上(这是默认情况,可以用memcache把这种数据放到内存里面,大公司会有专门的session统一管理服务器
  • 当客户端向服务器发出请求时,要求服务器端产生一个session时,服务器端会先检查一下,客户端的cookie里面有没有session_id,是否过期
  • 如果有这样的session_id的话,服务器端会根据cookie里的session_id把服务器的session检索出来
  • 如果没有这样的session_id的话,服务器端会重新建立一个
  • PHPSESSID是一串加了密的字符串,它的生成按照一定的规则来执行,同一客户端启动二次session_start的话,session_id是不一样的

通俗解释

Cookie保存在客户端浏览器中,而Session保存在服务器上

Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份

Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了

区别

  • 存放位置
    • cookie 存在于客户端,临时文件夹中
    • session存在于服务器的内存中,一个session域对象为一个用户浏览器服务
  • 安全性
    • cookie是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放
    • session存放于服务器的内存中,所以安全性好
  • 网络传输
    • cookie会传递消息给服务器
    • session本身存放于服务器,不会有传送流量
  • 时效性
    • cookie的生命周期是累计的,例如:从创建时,就开始计时,30分钟后,cookie生命周期结束
    • session的生命周期是间隔的
      • 从创建时,开始计时如在30分钟,没有访问session,那么session生命周期被销毁
      • 但是,如果在30分钟内(如在第25分钟时)访问过session,那么,将重新计算session的生命周期
  • 访问范围
    • cookie为多个用户浏览器共享
    • session为一个用户浏览器独享

常见数据存储方式

cookie组成
Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
1
  • NAME=VALUE
    • 这是每一个Cookie均必须有的部分
    • NAME是该Cookie的名称,VALUE是该Cookie的值
    • 在字符串“NAME=VALUE”中,不含分号、逗号和空格等字符
  • Expires=DATE
    • cookie有效终止日期
    • 该属性值DATE必须以特定的格式来书写,格式不争取,系统无法识别
  • Path=PATH:
    • Path属性定义了Web服务器上哪些路径下的页面可获取服务器设置的Cookie
  • **Domain=DOMAIN_NAME:
    • 它确定了哪些Internet域中的Web服务器可读取浏览器所存取的Cookie,即只有来自这个域的页面才可以使用Cookie中的信息
  • SECURE
    • 在Cookie中标记该变量,表明只有当浏览器和Web Server之间的通信协议为加密认证协议时,浏览器才向服务器提交相应的Cookie
    • 当前这种协议只有一种,即为HTTPS
cookie介绍
  • cookie数据始终在同源的http请求中携带(即使不需要)
  • cookie在浏览器和服务器间来回传递
  • 大小不超过4k
  • cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下
  • cookie也是在所有同源窗口中都是共享的

LocalStorage

  • 保存数据最大可以达到5M,甚至更多
  • 数据保存在本地磁盘(保存对象:JSON.stringfy()和JSON.parse())
  • 数据始终有效,窗口或浏览器关闭也一直保存
  • localStorage 在所有同源窗口中都是共享的

SessionStorage

  • 保存数据最大可以达到5M,甚至更多

  • 浏览器窗口(重点)

    • sessionStorage是在同源的同窗口(或tab)中,始终存在的数据
    • 仅在当前浏览器窗口关闭前有效
    • 只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在
    • 关闭窗口后,sessionStorage即被销毁
    • 同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的
    • sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面
特点 Cookie LocalStorage SessionStorage
数据的声明周期 一般由服务器生成,可设置失效时间。如果在浏览器生成,默认是关闭浏览器之后失效 除非被清楚,否则永久保存 仅在当前会话有效,关闭页面或浏览器后被清除
存放数据大小 4K 一般5MB 一般5MB
与服务端通信 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 仅在客户端中保存,不参与和服务器的通信(也可以选择提交到服务器…) 同 LocalStorage
作用 一般由服务器端生成,用于标识用户身份 用于浏览器端缓存数据 同 LocalStorage

内存泄漏

  • 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果

  • 指计算机可用内存的逐渐减少,当程序持续无法释放其使用的临时内存时就会发生。

  • JavaScript的web应用也会经常遇到在原生应用程序中出现的内存相关的问题,如泄漏和溢出,web应用也需要应对垃圾回收停顿

  • 尽管JavaScript使用垃圾回收进行自动内存管理,但有效的(effective)内存管理依然很重要。

JavaScript垃圾回收(GC)

  • 和C#、Java一样JavaScript有自动垃圾回收机制,也就是说执行环境会负责管理代码执行过程中使用的内存,在开发过程中就无需考虑内存分配及无用内存的回收问题了
  • JavaScript垃圾回收的机制:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是时时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

变量生命周期

  • 不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。
  • 一旦函数结束,局部变量就没有存在必要了,可以释放它们占用的内存。
  • 但是这样的情况往往很复杂,必须闭包,貌似函数结束了,其实没有,这种情况下就需要分析了

标记清除(mark and sweep)

  • 当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。
  • 原则上讲不能够释放进入环境的变量所占的内存,它们随时可能会被调用的到。
  • 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包)
  • 在这些完成之后仍存在标记的就是要删除的变量了,因为环境中的变量已经无法访问到这些变量了,然后垃圾回收器相会这些带有标记的变量机器所占空间。

引用计数(reference counting)

TIP

小峰哥初入编程,学习ios的时候,就是学的他们的引用计数,MRC和ARC,怀念

  • 在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。
  • 引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1
  • 如果该变量的值变成了另外一个,则这个值得引用次数减1
  • 当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。

引用计数缺点

  • 可能会造成循环引用的问题,比如:对象A有一个属性指向对象B,而对象B也有有一个属性指向对象A,这样相互引用,就会造成内存泄露

JavaScript垃圾回收触发

  • 垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨
  • 后期很多浏览器触发都是动态触发
  • 但是垃圾回收有时候是很不及时的,很多情况下效率也是很低的。

Chrome开发工具内存分析

TIP

由于Chrome版本不同,会造成教程中有些不可用的问题,请大家谅解。

调试工具截图如下:选择Memory即可

基本术语和基本概念

  • 介绍在内存分析时使用的常用术语,这些术语在为其它语言做内存分析的工具中也适用

对象大小(Object sizes)

  • 把内存想象成一个包含基本类型(像数字和字符串)和对象(关联数组)的图表。它可能看起来像下面这幅一系列相关联的点组成的图。

对象使用内存

  • 一个对象有两种使用内存的方法:

    • 对象自身直接使用
    • 隐含的保持对其它对象的引用,这种方式会阻止垃圾回收(简称GC)对那些对象的自动回收处理。
  • 相关调试工具中的显示:直接占用内存(Shallow Size)占用总内存(Retained Size),如图:

直接占用内存(Shallow Size)

  • 这个是对象本身占用的内存,不包括引用的对象占用的内存

  • 典型的JavaScript对象都会有保留内存用来描述这个对象和存储它的直接值。

  • 一般只有数组字符串会有明显的直接占用内存(Shallow Size)。

  • 但字符串和数组常常会在渲染器内存中存储主要数据部分,仅仅在JavaScript对象栈中暴露一个很小的包装对象。

  • 渲染器内存

    • 指你分析的页面在渲染的过程中所用到的所有内存
    • 页面本身的内存 + 页面中的JS堆用到的内存 + 页面触发的相关工作进程(workers)中的JS堆用到的内存。
    • 然而,通过阻止垃圾自动回收别的对象,一个小对象都有可能间接占用大量的内存

占用总内存(Retained Size)

  • 占用总内存包括引用的对象所占用的内存
  • 一个对象一但删除后,它引用的依赖对象就不能被**GC根(GC root)**引用到,它们所占用的内存就会被释放,一个对象占用总内存包括这些依赖对象所占用的内存。

内存图

  • 内存图由一个根部开始,可能是浏览器的window对象或Node.js模块Global对象。
  • 这些对象如何被内存回收不受用户的控制。

TIP

不能被GC根遍历到的对象都将被内存回收。

直接占用内存和占用总内存字段中的数据是用字节表示的

对象的占用总内存树

  • 堆是由各种互相关联的对象组成的网状结构。
  • 在数字领域,这种结构被称为内存图
  • 图是由**边缘(edges)连接着的节点(nodes)**组成的,他们都被贴了标签。

边缘(edges)

  • 标签名就是属性名

节点(nodes)

  • 节点的标签名是由创建他们的构造(constructor)函数的名称确定

距离(distance)

  • 是指对象到GC根的距离。
  • 如果同一个类型的所有对象的距离都一样,而有一小部分的距离却比较大,那么就可能出了些你需要进行调查的问题了。

支配对象(Dominators)

  • 支配对象就像一个树结构,因为每个对象都有一个支配者。
  • 一个对象的支配者可能不会直接引用它支配的对象,就是说,支配对象树结构不是图中的生成树。

拍一个快照

清除快照

切换快照视图

  • 一个快照可以根据不同的任务切换视图。
  • 下面是三个默认视图:
    • Summary(概要) - 通过构造函数名分类显示对象;
    • Comparison(对照) - 显示两个快照间对象的差异;
    • Containment(控制) - 可用来探测堆内容;
    • statistics:图表统计