晴明的博客园 GitHub      CodePen      CodeWars     

[js] 页面加载

window.onload

在文档装载完成后会触发 load 事件。此时,在文档中的所有对象都在DOM中,所有图片,脚本,链接以及子框都完成了装载。

DOMContentLoaded

IE9+

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。另一个不同的事件 load 应该仅用于检测一个完全加载的页面。 在使用 DOMContentLoaded 更加合适的情况下使用 load 是一个令人难以置信的流行的错误,所以要谨慎。

JQ中$(document).ready(function() { // ...代码... }) 其实监听的就是 DOMContentLoaded 事件
$(document).load(function() { // ...代码... }) 监听的是 load 事件。
在用JQ的时候,一般都会将函数调用写在ready方法内,就是页面被解析后,就可以访问整个页面的所有dom元素,可以缩短页面的可交互时间,提高整个页面的体验。

执行顺序:
interactive(readystatechange) -> interactive(DOMContentLoaded) -> complete(readystatechange) -> complete(load)

  document.addEventListener('DOMContentLoaded', function () {
    console.log(document.readyState + '(DOMContentLoaded)');
  })
  document.addEventListener('readystatechange', function () {
    console.log(document.readyState + '(readystatechange)');
  })
  // document.onreadystatechange = function () {
  //   console.log(document.readyState + '(onreadystatechange)');
  // }
  window.addEventListener('load', function () {
    console.log(document.readyState + '(load)');
  })
  // window.onload = function () {
  //   console.log(document.readyState + '(onload)');
  // }

dns-prefetch

IE10+,移动端未知

预先解析DNS
可以通过使用 rel 属性值为 link type 中的 dns-prefetch 的 <link> 标签来对特定域名进行预读取:

<link rel="dns-prefetch" href="http://example.com">

而且,<link> 元素也可以使用不完整的 URL 的主机名来标记预解析,但这些主机名前必需要有双斜线:

<link rel="dns-prefetch" href="//example.com">

强制对域名进行预读取在有的情况下很有用, 比如, 在网站的主页上,强制在整个网站上频繁引用的域名的预解析,即使它们不在主页本身上使用。即使主页的性能可能不受影响,这将提高整体站点性能。

preconnet

浏览器要建立一个连接,一般需要经过DNS查找,TCP三次握手和TLS协商(如果是https的话),这些过程都是需要相当的耗时的,所以preconnet,就是一项使浏览器能够预先建立一个连接,等真正需要加载资源的时候就能够直接请求了。
而一般形式就是

    <link rel="preconnect" href="//example.com">
    <link rel="preconnect" href="//cdn.example.com" crossorigin>

浏览器会进行以下步骤:

  1. 解释href的属性值,如果是合法的URL,然后继续判断URL的协议是否是http或者https否则就结束处理
  2. 如果当前页面host不同于href属性中的host,crossorigin其实被设置为anonymous(就是不带cookie了),如果希望带上cookie等信息可以加上crossorign属性,corssorign就等同于设置为use-credentials

prefetch

IE11,移动端支持也差.

浏览器会在空闲的时候,下载资源, 并缓存到disk。当有页面使用的时候,直接从disk缓存中读取。其实就是把决定是否和什么时间加载这个资源的决定权交给浏览器。

如果prefetch还没下载完之前,浏览器发现页面里引用了同样的资源,浏览器会再次发起请求,这样会严重影响性能的,加载了两次,所以不要在当前页面马上就要用的资源上用prefetch。

<link rel="prefetch" href="//example.com/next-page.html" as="html" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">

Subresource

IE不支持

subresource可以用来指定资源是最高优先级的.

<link rel="subresource" href="styles.css">

Chromium的文档这么解释:
和 "link rel=prefetch"的语义不同,"link rel=subresource"是一种新的连接关系。rel=prefetch指定了下载后续页面用到资源的低优先级,而rel=subresource则是指定当前页面资源的提前加载。

所以,如果资源是在当前页面需要,或者马上就会用到,则推荐用subresource,否则还是用prefetch。
类似preload.

prerender

IE11,整体兼容性差

可以让浏览器提前加载指定页面的所有资源。

prerender就像是在后台打开了一个隐藏的tab,会下载所有的资源、创建DOM、渲染页面、执行JS等等。如果用户进入指定的链接,隐藏的这个页面就会进入马上进入用户的视线。Google Search多年前就利用了这个特性实现了Instant Pages功能。

浏览器可能会

  • 分配少量资源对页面进行预渲染
  • 挂起部分请求直至页面可见时
  • 可能会放弃预渲染,如果消耗资源过多
    等等
    <link rel="prerender" href="//example.com/next-page.html">

preload

IE不支持

浏览器会在遇到如下link标签时,立刻开始下载main.js(不阻塞parser),并放在内存中,但不会执行其中的JS语句。
只有当遇到script标签加载的也是main.js的时候,浏览器才会直接将预先加载的JS执行掉。

<link rel="preload" href="/main.js" as="script">
<link rel="preload" href="/webfont.woff2" as="font">

preload特性检测

var DOMTokenListSupports = function(tokenList, token) {
  if (!tokenList || !tokenList.supports) {
    return;
  }
  try {
    return tokenList.supports(token);
  } catch (e) {
    if (e instanceof TypeError) {
      console.log("The DOMTokenList doesn't have a supported tokens list");
    } else {
      console.error("That shouldn't have happened");
    }
  }
};
 
var linkSupportsPreload = DOMTokenListSupports(document.createElement("link").relList, "preload");
if (!linkSupportsPreload) {
  // Dynamically load the things that relied on preload.
}

pr属性

dns-prefetch,preconnect,prefetch和prerender都支持一个pr属性(0.0到1.0范围的值),就是让浏览器能够判断优先加载那些资源,毕竟浏览器内部是有可用的连接池的,资源紧张的情况下只能加载优先级更高的资源。

defer , async

async IE10+

defer和async是script标签的两个属性,用于在不阻塞页面文档解析的前提下,控制脚本的下载和执行。

defer,async与下载时机也有关。

defer的执行时间是在所有元素解析完成之后,DOMContentLoaded 事件触发之前。

async的执行时间是在当前JS脚本下载完成后,所以多个async script是执行顺序是不固定的。async只能用于加载一些独立无依赖的代码,比如Google Analysis之类。

Preload,Prefetch 在 Chrome 之中的优先级

Chrome 有四种缓存: HTTP 缓存,内存缓存,Service Worker 缓存和 Push 缓存。preload 和 prefetch 都被存储在 HTTP 缓存中。

当一个资源被 preload 或者 prefetch 获取后,它可以从 HTTP 缓存移动至渲染器的内存缓存中。如果资源可以被缓存(比如说存在有效的cache-control 和 max-age),它被存储在 HTTP 缓存中可以被现在或将来的任务使用,如果资源不能被缓存在 HTTP 缓存中,作为代替,它被放在内存缓存中直到被使用。

脚本根据它们在文件中的位置是否异步、延迟或阻塞获得不同的优先级:

  1. 网络在第一个图片资源之前阻塞的脚本在网络优先级中是中级
  2. 网络在第一个图片资源之后阻塞的脚本在网络优先级中是低级
  3. 异步/延迟/插入的脚本(无论在什么位置)在网络优先级中是很低级

图片(视口可见)将会获得相对于视口不可见图片(低级)的更高的优先级(中级),所以某些程度上 Chrome 将会尽量懒加载这些图片。低优先级的图片在布局完成被视口发现时,将会获得优先级提升(但是注意已经在布局完成后的图片将不会更改优先级)。

preload 使用 as 属性加载的资源将会获得与资源 type 属性所拥有的相同的优先级。比如说,preload as="style" 将会获得比 as=“script” 更高的优先级。这些资源同样会受内容安全策略的影响(比如说,脚本会受到其 src 属性的影响)。

不带 as 属性的 preload 的优先级将会等同于异步请求。

可以通过Chrome的Network的Priority了解各种资源加载时的优先级属性.

posted @ 2018-05-18 20:40  晴明桑  阅读(226)  评论(0编辑  收藏  举报