1、 Babel的编译过程
Babel的作用是 从一种源码到另一种源码,充当转换编译器的作用,可以简述为解析(解析Js代码)-> 转换(解析和修改AST)-> 重建(将修改后的AST转换成另一种Js代码)
-
1、解析
解析步骤接受代码并输出AST,这一部分,与我们在大学中所学的编译原理颇为相关,这一步骤分为两个阶段:词法分析 和 语法分析
1、词法分析
- 词法分析阶段把字符串形式的代码转换为 **令牌(tokens)流**。- tokens是词法分析过程中不可分割的最小单元。例如var就是一个token对象,只能作为整体存在时有作用,语义上不可分解。
2、语法分析
- 语法分析阶段会把令牌流转换成AST的形式。这个阶段会使用令牌中的信息把它们转换成AST的表述结构。- **code(字符串形式代码) -> tokens(令牌流-词法单元序列) -> AST(抽象语法树)**- **Babel 使用 @babel/parser 解析代码,输入的 js 代码字符串根据 ESTree 规范生成 AST(抽象语法树)。**
2、转换
- 转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程。
Babel提供了@babel/traverse(遍历)方法维护这AST树的整体状态,并且可完成对其的替换,删除或者增加节点,这个方法的参数为原始AST和自定义的转换规则,返回结果为转换后的AST。
3、生成
代码生成步骤最终的AST转换成字符串形式的代码,同时还会创建源码映射(source maps)。
- 代码生成:通过深度优先遍历整个AST,然后构建可以表示转换后代码的字符串。
- Babel使用@babel/generator将修改后的AST转换成代码,生成过程可以对是否压缩以及是否删除注释等进行配置,并且支持sourceMap。
2、CDN的加速原理(缓存)
-
CDN(Content Delivery Network,内容分发网络)是构建在现有互联网基础之上的一层智能虚拟网络,通过在网络各处部署节点服务器,实现将源站内容分发至所有CDN节点,使用户可以就近获得所需的内容。
- CDN服务缩短了用户查看内容的访问延迟,提高了用户访问网站的响应速度与网站的可用性,解决了网络带宽小、用户访问量大、网点分布不均等问题。
- 当用户访问使用了CDN服务的网站时,本地DNS服务器通过CNAME方式(是域名系统(DNS)的一种记录,将一个域名(同名)映射到另一个域名(真实名称))将最终域名请求重定向到CDN服务。CDN通过一组预先定义好的策略(如内容类型、地理区域、网络负载均衡等),将当时能够最快响应用户的CDN节点IP地址提供给用户,使用户可以以最快的速度获得网站内容。
- 使用CDN后的HTTP请求处理过程如下
- CDN节点有缓存场景
、 - CDN节点无缓存场景

- CDN节点有缓存场景
- CDN缓存策略/CDN回源策略
- CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的Cache-control: max-age的字段来设置CDN边缘节点数据缓存时间。
- 当客户端向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向源站发出回源请求,从源站拉取最新数据,更新本地缓存,并将最新数据返回给客户端。
- CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。
- CDN缓存时间会对“回源率”产生直接的影响。若CDN缓存时间较短,CDN边缘节点上的数据会经常失效,导致频繁回源,增加了源站的负载,同时也增大的访问延时;若CDN缓存时间太长,会带来数据更新时间慢的问题。开发者需要增对特定的业务,来做特定的数据缓存时间管理。
- CDN缓存缺点
- 当网站更新时,如果CDN节点上数据没有及时更新,即便用户在浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。
CDN层级划分(中心层、边缘层)
-
HTTP 缓存的两个阶段
- 浏览器缓存一般分为两类:强缓存(也称本地缓存)和协商缓存(也称弱缓存)。
- 强缓存:浏览器发送请求前,会先去缓存里查看是否命中强缓存,如果命中,则直接从缓存中读取资源,不会发送请求到服务器。否则,进入下一步。
- 协商缓存:当强缓存没有命中时,浏览器一定会向服务器发起请求。服务器会根据 Request Header 中的一些字段来判断是否命中协商缓存。如果命中,服务器会返回 304 响应,但是不会携带任何响应实体,只是告诉浏览器可以直接从浏览器缓存中获取这个资源。如果本地缓存和协商缓存都没有命中,则从直接从服务器加载资源。

使用HTML Meta标签 Web开发者可以在HTML页面的节点中加入标签,如下

- 上述代码是告知浏览器当前页面不被缓存,但仅有IE才能识别这段meta的标签含义,其他大部分主流浏览器只识别“Cache-control:no-store”的meta标签。
- 在 IE 中识别到该 meta 标签含义,并不一定会在请求字段加上 Pragma,但的确会让当前页面每次都发新请求(仅限页面,页面上的资源则不受影响)。
HTTP 响应头 | 规则 | 消息报头 | 值/示例 | 类型 | 作用 | | —- | —- | —- | —- | —- | | 新鲜度 | Expires | Sun,16 Oct2016 06:43:02 GMT | 响应 | 告诉浏览器在过期时间前可以使用副本(有可能存在时间不一样的情况)。 | | | Pragma | no-cache | 响应 | 告诉浏览器忽略资源的缓存副本(HTTP1.1可以用Cache-control代替) | | | Cache-control | No-cache | 响应 | 告诉浏览器忽略资源的缓存副本,强制每次请求直接发送给服务器。 | | | | no-store | 响应 | 强制缓存在任何情况下都不要保留副本。 | | | | Max-age = [秒] | 响应 | 指明缓存副本的有效时长,从请求时间开始到过期时间之间的秒数。 | | | | public | 响应 | 任何途径的缓存者(本地缓存、代理服务器),可以无条件的缓存该资源。 | | | | private | 响应 | 只针对单个用户或实体(不同用户,窗口)缓存资源。 | | | | | | | | | Last-Modified | Sun,16 Oct2016 06:43:02 GMT | 响应 | 告诉浏览器当前资源的最后修改时间 | | | If-Modified-Since | Sun,16 Oct2016 06:43:02 GMT | 请求 | 如果浏览器第一次请求时响应中Last-Modified非空,第二次请求同一个资源时,会把它作为该项的值发给服务器。 | | | | | | | | 校验值 | Etag | 50b1c1d4f775c61:df3 | 响应 | 告诉浏览器当前资源在服务器的唯一标识符(生成规则由服务器决定)。 | | | If-None-Match | 50b1c1d4f775c61:df3 | 请求 | 如果浏览器第一次请求时响应中Etag非空,第二次请求同一个资源时,会把它作为该项的值发给服务器。 | | | | | | | | 辅助 | Vary | Accept-Encoding | 响应 | 辅助从多个缓存副本中筛选合适的版本。 | | | | | | |
Cache-control
- HTTP1.1 提出的特性,为了弥补 Expires 缺陷加入的,提供了更精确细致的缓存功能。
- 详细看几个常见的指令: max-age:功能和 Expires 类似,但是后面跟一个以“秒”为单位的相对时间,来供浏览器计算过期时间。 no-cache:提供了过期验证机制。

- Expires
- HTTP1.0 的特性,标识该资源过期的时间点,它是一个绝对值,格林威治时间(Greenwich Mean Time, GMT),即在这个时间点之后,缓存的资源过期
- 优先级:Cache-Control 优先级高于 Expires,为了兼容,通常两个头部同时设置
- 浏览器默认行为:其实就算 Response Header 中沒有设置 Cache-Control 和 Expires,浏览器仍然会缓存某些资源,这是浏览器的默认行为,是为了提升性能进行的优化,每个浏览器的行为可能不一致,有些浏览器甚至没有这样的优化。
- Last-Modified(Response Header)与 If-Modified-Since(Request Header)是一对报文头,属于 HTTP 1.0。
- If-Modified-Since 是一个请求首部字段,并且只能用在 GET 或者 HEAD 请求中。
- Last-Modified 是一个响应首部字段,包含服务器认定的资源作出修改的日期及时间。
- 当带着 If-Modified-Since 头访问服务器请求资源时,服务器会检查 Last-Modified,如果 Last-Modified 的时间早于或等于 If-Modified-Since 则会返回一个不带主体的 304 响应,否则将重新返回资源。

- ETag 与 If-None-Match 是一对报文头,属于 HTTP 1.1
- ETag 是一个响应首部字段,它是根据实体内容生成的一段 hash 字符串,标识资源的状态,由服务端产生。
- If-None-Match 是一个条件式的请求首部。如果请求资源时在请求首部加上这个字段,值为之前服务器端返回的资源上的 ETag,则当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的时候,服务器才会返回带有所请求资源实体的 200 响应,否则服务器会返回不带实体的 304 响应。

- Etag能解决什么问题?
- Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在 1 秒钟以内,被修改多次的话,它将不能准确标注文件的新鲜度。
- 某些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),但 Last-Modified 却改变了,导致文件没法使用缓存。
- 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
- 优先级:ETag 优先级比 Last-Modified 高,同时存在时会以 ETag 为准。

- 缓存位置
- 浏览器可以在内存、硬盘中开辟一个空间用于保存请求资源副本。我们经常调试时在 DevTools Network 里看到 Memory Cache(內存缓存)和 Disk Cache(硬盘缓存),指的就是缓存所在的位置。请求一个资源时,会按照优先级(Service Worker -> Memory Cache -> Disk Cache -> Push Cache)依次查找缓存,如果命中则使用缓存,否则发起请求。
- 200 from memory cache
- 表示不访问服务器,直接从内存中读取缓存。因为缓存的资源保存在内存中,所以读取速度较快,但是关闭进程后,缓存资源也会随之销毁,一般来说,系统不会给内存分配较大的容量,因此内存缓存一般用于存储较小文件。同时内存缓存在有时效性要求的场景下也很有用(比如浏览器的隐私模式)。
- 200 from disk cache
- 表示不访问服务器,直接从硬盘中读取缓存。与内存相比,硬盘的读取速度相对较慢,但硬盘缓存持续的时间更长,关闭进程之后,缓存的资源仍然存在。由于硬盘的容量较大,因此一般用于存储大文件。
- 下图可清晰看出差别:
- 200 from prefetch cache
- 在 preload 或 prefetch 的资源加载时,两者也是均存储在 http cache,当资源加载完成后,如果资源是可以被缓存的,那么其被存储在 http cache 中等待后续使用;如果资源不可被缓存,那么其在被使用前均存储在 memory cache。

- CDN Cache
- 以腾讯 CDN 为例:X-Cache-Lookup:Hit From MemCache 表示命中 CDN 节点的内存;X-Cache-Lookup:Hit From Disktank 表示命中 CDN 节点的磁盘;X-Cache-Lookup:Hit From Upstream 表示没有命中 CDN。

- 整体流程
- 浏览器缓存一般分为两类:强缓存(也称本地缓存)和协商缓存(也称弱缓存)。
-
IndexDB
- IndexedDB 就是浏览器提供的本地数据库,能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API。- 异步 API 方法调用完后会立即返回,而不会阻塞调用线程。要异步访问数据库,要调用 window 对象 indexedDB 属性的 open() 方法。该方法返回一个 IDBRequest 对象 (IDBOpenDBRequest);异步操作通过在 IDBRequest 对象上触发事件来和调用程序进行通信。- 常用异步 API 如下:
LocalStorage
- localStorage 属性允许你访问一个 Document 源(origin)的对象 Storage 用于存储当前源的数据,除非用户人为清除(调用 localStorage api 或则清除浏览器数据), 否则存储在 localStorage 的数据将被长期保留。
Service Worker
- SW 从 2014 年提出的草案到现在已经发展很成熟了,基于 SW 做离线缓存,让用户能够进行离线体验,消息推送体验,离线缓存能力涉及到 Cache 和 CacheStorage 的概念,篇幅有限,不展开了。
SessionStorage
- sessionStorage 属性允许你访问一个 session Storage 对象,用于存储当前会话的数据,存储在 sessionStorage 里面的数据在页面会话结束时会被清除。页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。


