Page lifecycle: DOMContentLoaded, load, beforeunload, unload(翻译)

在HTML页面的生命周期中,会触发三个重要的事件

  • DOMContentLoaded: 当HTML文档已经完全加载并解析完成后触发,并且不用等待样式表、图片、子框架加载完成。
  • load:当浏览器加载解析完所有资源,包括图片文件,样式表文件
  • beforeunload/unload: 当用户离开页面

它们的可能适用场景:

  • DOMContentLoaded: 所有DOM元素已经就绪,通过handler查询DOM节点,初始化界面
  • load: 当图片加载完成,获取图片尺寸
  • beforeunload/unload: 可以检查用户是否保存了变更,并且询问是否确定离开页面

探究这些事件的一些细节:

1. DOMContentLoaded与image

Hello World

当我们去加载一个这样的页面时候,DOMContentLoaded不会等待图片的加载才去触发。

first.gif

2. DOMContentLoaded与script

当浏览器加载HTML时遇到script标签,会停止构建DOM而是立即加载执行script标签内容。DOMContentLoaded事件会在所有script内容全部执行完触发。
例如:

// HTML

    

// index.js
alert('this is the external script')
second.gif

从外部加载资源的script标签,通过设置async和defer属性,可以告知浏览器不要等待script标签的加载和运行。设置defer的script脚本会先于DOMContentLoaded事件执行, 这一点上似乎和不设置defer属性是一样的情况

// HTML

    
third.gif

设置async属性时,可能会在DOMContentLoaded事件触发之前或者之后执行

// HTML

    
fourth.gif

3. DOMContentLoaded与style

外部加载的样式表不会影响构造DOM,DOMContentLoaded事件不会等待样式表的加载。
但是有一个陷阱:当link标签加载一个样式表,在它后面的那个script标签必须要等待样式表文件的加载才会执行。

Hello World

fifth.gif

现在我们发现,DOMContentLoaded在实际场景中可能还是也需要等待样式文件的加载后才触发

4. 浏览器的自动填充

Firefox, Chrome 还有Opera的自动填充form表单都是基于DOMContentLoaded事件的。
举个例子,如果页面有一个登录表单(用户名与密码), 浏览器可能会记住密码这些值。刷新页面后,再次触发DOMContentLoaded就会完成自动填充的效果。
所以如果DOMContentLoaded事件因为script脚本的执行而延迟了一段时间才触发,那么自动填充也要延迟那么一段时间才会完成。

4. window.onload

window对象的load事件是当所有页面资源就绪后才会触发(包括外部样式表、图片、脚本等等)

4. window.onunload

当用户离开页面,window对象的unload事件就会被触发。我们可以在用户离开页面是设置一个提示,但是不能取消这次离开的操作。
因此我们需要另一个事件onbeforeunload

4. window.onbeforeunload

// HTML

Hello World

another page

通过注册beforeunload事件的处理函数,就可以让用户想离开页面的时候,弹出提示框让用户选择是否马上离开了。需要注意的在写法上:

     // success
      window.onbeforeunload = () => {
        return "There are unsaved changes. Leave now?"
      }
      // fail
      window.addEventListener('beforeunload', event => {
        return "There are unsaved changes. Leave now?"
      })
      // success
      window.addEventListener('beforeunload', event => {
        event.returnValue =  "There are unsaved changes. Leave now?"
      })

对于第一种DOM0级处理程序,函数返回值不为null或者undefined都有弹出框。DOM2级的处理程序,则是event.returnValue属性的值不为null或者undefined。
另外要注意的是,像chrome或者Firefox会忽略返回的字符串而显示浏览器预设的信息。这么做是为了sheer safety(黑人问号,不知道怎么翻)。

7.readyState

如果我们在文档已经load的情况下监听DOMContentLoaded事件,并设置处理程序会怎么样?
处理程序肯定不会执行。
某些情况下,我们没法确定文档是否ready,举个例子,外部引入的script标签,设置了async属性异步执行。根据网络情况,script脚本可能会document解析的某个阶段执行,那么就有必要了解一下document.readyState
document.readyState有三个值

  • 'loading': document等在加载
  • 'interactive': document被完全解析
  • 'complete': document被完全解析,并且所有外部资源都加载完毕

因此可以通过检查document.readyState,并且设置处理程序来完成document已经ready后的动作。

function work() { /*...*/ }

if (document.readyState == 'loading') {
  document.addEventListener('DOMContentLoaded', work);
} else {
  work();
}

readystatechange事件会在document的state变化时触发,所以通过监听该事件,我们可以了解state在什么情况下变化。







具体例子
输出:
[1] initial readyState:loading
[2] readyState:interactive
[2] DOMContentLoaded
[3] iframe onload
[4] readyState:complete
[4] img onload
[4] window onload
总结起来在DOMContentLoaded之前document.readyState变成interactive;而在document.readyState变成complete之后,window.onload也随之触发。

小结:

1. 监听document对象的DOMContentLoaded的事件,会在页面所有DOM已经ready的情况下触发,我们在这个时候,开始脚本执行($(document).ready(handler))

  • 所有脚本除了外部引入的有async或defer属性的部分外,都会执行。
  • 图片及其他资源则继续加载 ####

2. window对象的load事件则会在页面所有资源加载完毕后触发,我们也少用到它

3. window对象的beforeunload事件,会在用户打算离开页面时触发,弹出一个对话框并包含一个问题让用户进行判断

4. window对象的unload会在用户最终离开时触发,但是似乎派不上什么用场

5. document.readyState输出当前document的state,监听readystatechange事件可以跟踪document的state。

  • loading: document正在加载
  • interactive: 除一些外部资源外document已经解析完成
  • complete: document和外部资源全部加载完成 ####

原文连接在这儿

文中的例子在这儿

你可能感兴趣的:(Page lifecycle: DOMContentLoaded, load, beforeunload, unload(翻译))