同域下如何让循环等待iframe加载完成后再加载下一个URL?
问题描述
我通过顶层框架的脚本(同域环境),将一系列基于日期的URL加载到iframe中提取每页数据,当前使用如下while循环遍历日期并设置iframe的src:
var start = new Date("01/01/2024"); var end = new Date("01/31/2024"); var loop = new Date(start); while(loop <= end){ $("#iframe").attr("src", "data.htm?" + loop); $("#iframe").ready(function() { // Do something in iframe e.g. $("#iframe").contents().find("#export").click() }); var newDate = loop.setDate(loop.getDate() + 1); loop = new Date(newDate); }
但循环不会等待iframe加载完成及执行指定操作后,再加载下一个日期对应的URL。推测iframe的ready/load函数仅用于绑定事件,无法阻止循环推进。请问实现这一等待逻辑的最优/最高效方法是什么?(可使用或不使用jQuery)
解决方案
循环是同步执行的,而iframe加载属于异步操作,必须通过异步流程控制实现逐个等待加载完成。以下是两种高效实现方式:
方法1:Async/Await + Promise(推荐,代码清晰易维护)
将iframe加载过程封装为Promise,通过async函数配合await逐个处理日期,逻辑直观。
原生JS版本
const start = new Date("01/01/2024"); const end = new Date("01/31/2024"); // 封装iframe加载完成的Promise function loadIframeWithDate(date) { return new Promise((resolve) => { const iframe = document.getElementById("iframe"); // 移除之前的load事件监听,避免重复绑定 iframe.removeEventListener("load", onLoad); function onLoad() { // 执行数据提取操作 iframe.contentDocument.getElementById("export").click(); // 操作完成后resolve,推进下一个日期 resolve(); } iframe.addEventListener("load", onLoad); // 设置新src触发加载 iframe.src = `data.htm?${date}`; }); } // 逐个处理日期的异步函数 async function processDates() { let currentDate = new Date(start); while (currentDate <= end) { await loadIframeWithDate(currentDate); // 推进到下一天 currentDate.setDate(currentDate.getDate() + 1); } } // 启动流程 processDates();
jQuery版本
const start = new Date("01/01/2024"); const end = new Date("01/31/2024"); function loadIframeWithDate(date) { return new Promise((resolve) => { const $iframe = $("#iframe"); // 解绑之前的load事件 $iframe.off("load"); $iframe.on("load", function() { // 执行操作 $(this).contents().find("#export").click(); resolve(); }); $iframe.attr("src", `data.htm?${date}`); }); } async function processDates() { let currentDate = new Date(start); while (currentDate <= end) { await loadIframeWithDate(currentDate); currentDate.setDate(currentDate.getDate() + 1); } } processDates();
方法2:递归调用(兼容旧环境)
若运行环境不支持ES6+的async/await,可通过递归实现,每次iframe加载完成后触发下一个日期的处理。
原生JS版本
const start = new Date("01/01/2024"); const end = new Date("01/31/2024"); let currentDate = new Date(start); const iframe = document.getElementById("iframe"); function processNextDate() { if (currentDate > end) return; // 终止递归 iframe.removeEventListener("load", onLoad); function onLoad() { // 执行数据操作 iframe.contentDocument.getElementById("export").click(); // 推进日期并递归调用 currentDate.setDate(currentDate.getDate() + 1); processNextDate(); } iframe.addEventListener("load", onLoad); iframe.src = `data.htm?${currentDate}`; } // 启动递归流程 processNextDate();
核心注意点
- 必须移除/解绑之前的
load事件监听,避免重复绑定导致操作多次执行 - 使用
load事件替代ready:ready仅监听DOM就绪,load会等待iframe内所有资源加载完成,更适合操作页面元素的场景 - 异步流程控制是关键:要么通过async/await等待Promise完成,要么通过递归在加载完成后触发下一次操作
内容的提问来源于stack exchange,提问作者highlander
相关产品推荐
相关产品推荐

