页面声明周期

页面声明周期

1. DOMContentLoaded 事件

DOMContentLoaded —— 浏览器已完全加载 HTML,并构建了 DOM 树,但像 <img> 和样式表之类的外部资源可能尚未加载完成

DOMContentLoaded 事件发生在 document 对象上,必须使用 addEventListener 来捕获

  • 具有 async 特性(attribute)的脚本不会阻塞 DOMContentLoaded
  • 使用 document.createElement('script') 动态生成并添加到网页的脚本也不会阻塞 DOMContentLoaded
  • 外部样式表以及图片和其他资源不会阻塞 DOMContentLoaded
  • <script>...</script><script src="..."></script> 之类的脚本会阻塞 DOMContentLoaded,浏览器将等待它们执行结束
<style>
    img {
        width: auto;
    }
</style>
<script>
    function read() {
        // 图片以及样式不会阻塞加载
        console.log(img.offsetWidth, img.offsetHeight); // 0 0
        console.log('DOM ready');
        console.log(window.getComputedStyle(img).width); // 0px
    }

    // DOMContentLoaded 发生在document对象上
    document.addEventListener("DOMContentLoaded", read)
</script>

<script>
    // script脚本文件会阻塞加载
    // 必须等待script甲苯加载完成,然后加载
    console.log('script')
</script>

<img id="img" src="https://w.wallhaven.cc/full/x8/wallhaven-x8ye3z.jpg" alt="">

2. load事件

当整个页面,包括样式、图片和其他资源被加载完成时,会触发 window 对象上的 load 事件

当页面未加载完成时,script 标签如果在文档上,js 脚本中将无法获取到元素,可以通过 onload 事件等文档元素加载完成再使用

<style>
    .box {
        width: 200px;
        height: 200px;
    }
</style>
<script>
    // script标签阻塞先执行,文档还未加载完,获取为null
    let box = document.querySelector('.box');
    console.log(box); // null
    
    // onload事件等样式图片其它资源加载完成后执行
    window.onload = function() {
        let box = document.querySelector('.box');
        console.log(box);
        // <div class="box"></div>
    }
</script>

<div class="box"></div>

3. beforeunload 事件

如果访问者触发了离开页面的导航或试图关闭窗口,beforeunload 事件将会触发

event.preventDefault()beforeunload 处理程序中不起作用

window.onbeforeunload = function() {
  return false;
};

window.onbeforeunload = function(e) {
  // 阻止无效
  e.preventDefault();
  return "有未保存的值。确认要离开吗?";
};

4. unload 事件

load 事件相对的 unload 事件,unload 事件会在文档卸载完成后触发

unload 事件一般是在从一个页面导航到另一个页面时触发,最常用于清理引用,以免内存泄露

页面资源的清除工作会在 unload 事件之后进行

window.addEventListener("unload", function() {})

5. readyState 状态

document.readyState 属性提供当前加载状态的信息

  • loading —— 文档正在被加载
  • interactive —— 文档被全部读取
  • complete —— 文档被全部读取,并且所有资源(例如图片等)都已加载完成
console.log(document.readyState); // loading
        
// readyState获取文档加载状态
document.addEventListener('DOMContentLoaded', function () {
    console.log(document.readyState); // interactive

})

window.onload = function () {
    console.log(document.readyState); // complete
}

6. resize 事件

window.onresize = function(){}

当浏览器窗口被缩放到新的高度或者宽度时,会触发 resize 事件

这个事件在 window 上触发,需要通过在 window 或者 body 上添加 onresize 事件来指定事件处理程序

// onresize 当浏览器窗口高度宽度发生变化时触发
window.addEventListener("resize", function() {
    console.log('触发')
})

7. error 事件

  • window 上,当 js 脚本报错时触发
  • img 元素上,当无法加载指定图片时触发
  • 在元素对象上,无法加载对应对象时触发
  • 在多窗口下,一个或多个窗口无法完成加载时触发
// 当js脚本发生错误时则执行error事件
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // 没有这个脚本
document.head.append(script);

script.onerror = function() {
	console.log("Error loading " + this.src); // Error loading https://example.com/404.js
};

// 当图片无法加载时执行error事件
let img = document.createElement('img');
img.src = "https://js.cx/clipart/traisn.gif";

img.onload = function() {
	console.log('加载失败')
};

img.onerror = function() {
	console.log(`Error loading` + this.src);
};

8. async,defer

当浏览器加载 HTML 时遇到 <script>...</script> 标签,浏览器就不能继续构建 DOM,它必须立刻执行此脚本

对于外部脚本 <script src="..."></script> 浏览器必须等脚本下载完,并执行结束,之后才能继续处理剩余的页面

该机制导致的问题:

  • 脚本不能访问到位于它们下面的 DOM 元素,因此,脚本无法给它们添加处理程序等

  • 如果页面顶部有一个笨重的脚本,它会阻塞页面,在该脚本下载并执行结束前,用户都不能看到页面内容

解决方案:

  • js 脚本放在文档标签底部,它可以访问到它上面的元素,并且不会阻塞页面显示内容
<script>
    // 脚本不能访问到位于它们下面的 DOM 元素
    let box = document.querySelector('.box')
    console.log(box); // null
</script>
<div class="box"></div>
<!-- 放到dom元素下面来获取 -->
<script>
    // 脚本不能访问到位于它们下面的 DOM 元素
    let box1 = document.querySelector('.box')
    console.log(box1); // <div class="box"></div>
</script>

8-1 defer

defer 特性告诉浏览器不要等待脚本。相反,浏览器将继续处理 HTML,构建 DOM。脚本会在后台下载,然后等 DOM 构建完成后,脚本才会执行

**Tips:**如果 <script> 脚本没有 src,则会忽略 defer 特性

  • 具有 defer 特性的脚本不会阻塞页面
  • 具有 defer 特性的脚本总是要等到 DOM 解析完毕,但在 DOMContentLoaded 事件之前执行
  • 具有 defer 特性的脚本按照文档顺序加载(它们在文档中的顺序)
<script>
    document.addEventListener("DOMContentLoaded", function () {
        console.log('DOMContentLoaded')
    })
</script>
<script defer src="./index.js"></script>
<!-- defer 先执行 会等待dom解析完毕 -->
<!-- 能获取到dom元素 -->
<!-- 文档中的顺序加载 -->
<script defer src="./last.js"></script>

8-2 async

async 特性与 defer 有些类似,也能够让脚本不阻塞页面

**Tips:**如果 <script> 脚本没有 src,则会忽略 async 特性

  • 浏览器不会因 async 脚本而阻塞

  • 其他脚本不会等待 async 脚本加载完成,async 脚本也不会等待其他脚本

  • 具有 async 特性的脚本按照加载优先顺序,脚本在文档中的顺序不重要 —— 先加载完成的先执行

  • DOMContentLoaded 和异步脚本不会彼此等待

    • DOMContentLoaded 可能会发生在异步脚本之前(异步脚本在页面完成后才加载完成)

    • DOMContentLoaded 也可能发生在异步脚本之后(异步脚本很短,或者是从 HTTP 缓存中加载的)

<script>
    document.addEventListener("DOMContentLoaded", function () {
        // async 与 DOMContentLoaded 两者互不等待
        // 有可能 async 在 DOMContentLoaded 前执行
        // 有可能 async 在 DOMContentLoaded 后执行
        setTimeout(function () {
            console.log('DOMContentLoaded')
        }, 1000)
    })
</script>
<script async src="./index.js"></script>
<!-- async 能获取到dom元素 -->
<!-- 加载优先顺序 -->
<script async src="./last.js"></script>

8-3 动态脚本

使用 JavaScript 动态地创建一个脚本,并将其添加到文档中,默认情况下,动态脚本的行为是异步的

  • 它们不会等待任何东西,也没有什么东西会等它们
  • 先加载完成的脚本先执行(加载优先顺序)
  • 也可通过 script.async = false 来改变加载规则,脚本将按照脚本在文档中的顺序执行
<script>
    document.addEventListener("DOMContentLoaded", function () {
        setTimeout(function () {
            console.log('DOMContentLoaded')
        }, 3000)
    })
</script>
<div class="box"></div>
<script>
    function loadScript(src) {
        let script = document.createElement('script');
        script.src = src;
        script.async = false;
        document.body.append(script);
    }
    loadScript("./index.js");
    loadScript("./last.js");
</script>
// index.js
setTimeout(() => {
    console.log('index.js');
    console.log(document.querySelector('.box'));
}, 1000)

// last.js
setTimeout(() => {
    console.log('last.js')
}, 1000)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值