元素等待器的简易方法
前言
元素等待器是什么? 现在网页基本都是基于框架去编写的, 那么 Dom 元素就并非直接写在 HTML 中的, 而是通过 JS 渲染出来的. 那么就会出现一个问题, 在 load
/ DOMContentLoaded
事件触发时, 网页上并非是完全的 HTML 结构, 还有一些元素仍然在异步载入中. 所以现在的脚本如果需要在页面载入时操作 Dom , 那么就需要通过一个元素等待器去等待元素载入后, 再进行后续的操作.
MutationObserver
是一个很好的解决方案, 但是有一个问题是, 写起来确实有点繁琐. 如果不是直接导入函数库/已经写好的函数, 那么手写的话会非常的麻烦. 只写一遍还好说, 但是如果每次都要写的话会很麻烦.
有时候想写一些简单的脚本, 不想开一个新的项目, 想直接在网页编辑器中编写代码, 又不想依赖第三方库的时候, 想要获取异步载入的元素怎么办呢? 最简单的方法: 轮询.
第三库的异步元素等待器: ElementGetter .
MutationObserve 知识
粗暴延时
// 函数入口
const main = () => {
const dom = document.querySelector( '#app' );
// any code
};
// 粗暴延时5s开始运行函数
setTimeout( main, 5_000 );
轮询
轮询 本质上是对于粗暴延时的简单优化, 因为延时不仅反应慢, 并且也有可能等待后元素仍然没有载入导致函数错误.
// 函数入口
const main = () => {
// any code
};
// 每 500 ms 查询一次元素载入状态
const getterTimer = setInterval( () => {
const dom = document.querySelector( '#app' );
// 如果元素载入
if ( dom ) {
// 清除定时器
clearInterval( getterTimer );
// 运行函数
main();
}
}, 500 );
这样, 只需要一次定时器的开启和关闭操作, 就可以完成等待异步元素载入的操作. 在一些随便写写的简单脚本上, 会比手写 MutationObserver
会方便不少.
当然, 如果开一个项目写脚本, 能用 MutationObserver
还是优先选用 MutationObserver
去载入函数.
简单封装轮询
虽然 js/ts 主流的类型语法库还没有支持, 但是 Promise.withResolvers()
是已经在所有浏览器全面支持的, 是可以直接使用的.
/**
* 获取异步载入的元素
*
* @parma {string} selector 元素选择器
* @parma {number} [delayPerMs = 500] 轮询延时
*
* @Return {Promise<Element>} 载入的元素
* */
function elementGetter( selector, delayPerMs = 500 ) {
let { promise, resolve, reject } = Promise.withResolvers();
// 轮询获取元素载入情况
const getterTimer = setInterval( () => {
const dom = document.querySelector( '#app' );
// 如果元素载入
if ( dom ) {
// 清除定时器
clearInterval( getterTimer );
// 兑现 promise
resolve( dom );
}
}, delayPerMs );
// 返回 Promise
return promise;
}