javascript基础学习系列四百五十六: readystatechange 事件

本文详细解释了浏览器事件如readystatechange,load,pageshow,pagehide以及hashchange在DOM加载过程中的行为,包括readyState的可能值,它们的触发顺序和与外部资源的关系,以及Firefox的往返缓存机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IE 首先在 DOM 文档的一些地方定义了一个名为 readystatechange 事件。这个有点神秘的事件旨在提供文档或元素加载状态的信息,但行为有时候并不稳定。支持 readystatechange 事件的每个对象都有一个 readyState 属性,该属性具有一个以下列出的可能的字符串值。
 uninitialized:对象存在并尚未初始化。
 loading:对象正在加载数据。
 loaded:对象已经加载完数据。
 interactive:对象可以交互,但尚未加载完成。
 complete:对象加载完成。
看起来很简单,其实并非所有对象都会经历所有 readystate 阶段。文档中说有些对象会完全跳过某个阶段,但并未说明哪些阶段适用于哪些对象。这意味着 readystatechange 事件经常会触发不到4 次,而 readyState 未必会依次呈现上述值。
在 document 上使用时,值为"interactive"的 readyState 首先会触发 readystatechange事件,时机类似于 DOMContentLoaded。进入交互阶段,意味着 DOM 树已加载完成,因而可以安全地交互了。此时图片和其他外部资源不一定都加载完了。可以像下面这样使用 readystatechange 事件:

 if (document.readyState == "interactive") { 
 console.log("Content loaded"); 
 } 
}); 

这个事件的 event 对象中没有任何额外的信息,连事件目标都不会设置。
在与 load 事件共同使用时,这个事件的触发顺序不能保证。在包含特别多或较大外部资源的页面中,交互阶段会在 load 事件触发前先触发。而在包含较少且较小外部资源的页面中,这个readystatechange 事件有可能在 load 事件触发后才触发。
让问题变得更加复杂的是,交互阶段与完成阶段的顺序也不是固定的。在外部资源较多的页面中,很可能交互阶段会早于完成阶段,而在外部资源较少的页面中,很可能完成阶段会早于交互阶段。因此,实践中为了抢到较早的时机,需要同时检测交互阶段和完成阶段。比如:

 if (document.readyState == "interactive" || 
 document.readyState == "complete") { 
 document.removeEventListener("readystatechange", arguments.callee); 
 console.log("Content loaded"); 
 } 
}); 

当 readystatechange 事件触发时,这段代码会检测 document.readyState 属性,以确定当前是不是交互或完成状态。如果是,则移除事件处理程序,以保证其他阶段不再执行。注意,因为这里的事件处理程序是匿名函数,所以使用了 arguments.callee 作为函数指针。然后,又打印出一条表示内容已加载的消息。这样的逻辑可以保证尽可能接近使用 DOMContentLoaded 事件的效果。
pageshow 与 pagehide 事件Firefox 和 Opera 开发了一个名为往返缓存(bfcache,back-forward cache)的功能,此功能旨在使用浏览器“前进”和“后退”按钮时加快页面之间的切换。这个缓存不仅存储页面数据,也存储 DOM 和JavaScript 状态,实际上是把整个页面都保存在内存里。如果页面在缓存中,那么导航到这个页面时就不会触发 load 事件。通常,这不会导致什么问题,因为整个页面状态都被保存起来了。不过,Firefx决定提供一些事件,把往返缓存的行为暴露出来。
第一个事件是 pageshow,其会在页面显示时触发,无论是否来自往返缓存。在新加载的页面上,pageshow 会在 load 事件之后触发;在来自往返缓存的页面上,pageshow 会在页面状态完全恢复后触发。注意,虽然这个事件的目标是 document,但事件处理程序必须添加到 window 上。下面的例子展示了追踪这些事件的代码:

 let showCount = 0; 
 window.addEventListener("load", () => { 
 console.log("Load fired"); 
 }); 
 window.addEventListener("pageshow", () => { 
 showCount++; 
 console.log(`Show has been fired ${showCount} times.`); 
 }); 
})(); 

这个例子使用了私有作用域来保证 showCount 变量不进入全局作用域。在页面首次加载时,showCount 的值为 0。之后每次触发 pageshow 事件,showCount 都会加 1 并输出消息。如果从包含
以上代码的页面跳走,然后又点击“后退”按钮返回以恢复它,就能够每次都看到 showCount 递增的值。这是因为变量的状态连同整个页面状态都保存在了内存中,导航回来后可以恢复。如果是点击了浏览器的“刷新”按钮,则 showCount 的值会重置为 0,因为页面会重新加载。
除了常用的属性,pageshow 的 event 对象中还包含一个名为 persisted 的属性。这个属性是一个布尔值,如果页面存储在了往返缓存中就是 true,否则就是 false。可以像下面这样在事件处理程序中检测这个属性:

 let showCount = 0; 
 window.addEventListener("load", () => { 
 console.log("Load fired"); 
 }); 
 window.addEventListener("pageshow", () => { 
 showCount++; 
 console.log(`Show has been fired ${showCount} times.`, 
 `Persisted? ${event.persisted}`); 
 }); 
})(); 

通过检测 persisted 属性可以根据页面是否取自往返缓存而决定是否采取不同的操作。
与 pageshow 对应的事件是 pagehide,这个事件会在页面从浏览器中卸载后,在 unload 事件之前触发。与 pageshow 事件一样,pagehide 事件同样是在 document 上触发,但事件处理程序必须被
添加到 window。event 对象中同样包含 persisted 属性,但用法稍有不同。比如,以下代码检测了event.persisted 属性:

 console.log("Hiding. Persisted? " + event.persisted); 
}); 

这样,当 pagehide 事件触发时,也许可以根据 persisted 属性的值来采取一些不同的操作。对pageshow 事件来说,persisted 为 true 表示页面是从往返缓存中加载的;而对 pagehide 事件来说,
persisted 为 true 表示页面在卸载之后会被保存在往返缓存中。因此,第一次触发 pageshow 事件时 persisted 始终是 false,而第一次触发 pagehide 事件时 persisted 始终是 true(除非页面不
符合使用往返缓存的条件)。
hashchange 事件
HTML5 增加了 hashchange 事件,用于在 URL 散列值(URL 最后#后面的部分)发生变化时通知开发者。这是因为开发者经常在 Ajax 应用程序中使用 URL 散列值存储状态信息或路由导航信息。
onhashchange 事件处理程序必须添加给 window,每次 URL 散列值发生变化时会调用它。event对象有两个新属性:oldURL 和 newURL。这两个属性分别保存变化前后的 URL,而且是包含散列值的完整 URL。下面的例子展示了如何获取变化前后的 URL:

 console.log(`Old URL: ${event.oldURL}, New URL: ${event.newURL}`); 
}); 
如果想确定当前的散列值,最好使用 location 对象:
window.addEventListener("hashchange", (event) => { 
 console.log(`Current hash: ${location.hash}`); 
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值