有一个 JavaScript 函数,其中我对代码的控制为零,它调用了我编写的函数。我的函数使用 DOM 生成 iFrame,定义它的 src,然后将其附加到另一个 DOM 元素。但是,在我的函数返回并因此允许继续执行包含函数之前,必须完全加载 iFrame。
以下是我尝试过的事情以及为什么它们不起作用:
1. SetTimeout 选项:
99.999% 的时间,这就是答案。事实上,在我指导 JavaScript 的过去十年中,我一直坚持认为代码总是可以被重构以使用这个选项,并且从不相信存在不这样的场景。嗯,我终于找到了一个!问题是因为我的函数被内联调用,如果在我的 iFrame 完成加载之前执行下一行,它将完全中性我的脚本,并且从我的脚本完成的那一刻起,外部脚本继续。各种回调不起作用
2.“什么都不做”循环:
这个选项你使用while(//iFrame is not loaded){//do nothing}。从理论上讲,这在加载框架之前不会返回。问题是,由于这会占用所有资源,因此 iFrame 永远不会加载。这个技巧,虽然非常不专业,肮脏等当你只需要一个内联延迟时会起作用,但因为我需要一个外部线程来完成,所以它不会。
在 FF 中,几秒钟后,它会暂停脚本并弹出一个警报,指出有一个无响应的脚本。当该警报出现时,iFrame 能够加载,然后我的函数能够返回,但是让浏览器冻结 10 秒,然后要求用户正确消除错误是不行的。
3.模型对话:
我受到以下事实的启发,即 FF 弹出窗口允许 iFrame 在停止函数执行的同时加载,并考虑它,我意识到这是因为模态对话是一种暂停执行但允许其他线程继续的方式!太棒了,所以我决定尝试其他模态选项。像 alert() 这样的东西工作得很好!当它弹出时,即使只有 1/10 秒,iFrame 也能完成,并且一切正常。万一 1/10 秒不够用,我可以将模型对话放在解决方案 2 的 while 循环中,这样可以确保 iFrame 及时加载。甜吗?除了我现在必须弹出一个非常不专业的对话框让用户关闭以运行我的脚本这一事实。我与自己争论这个行动的成本/收益,但后来我遇到了一个场景,我的代码在一个页面上被调用了 10 次!在访问页面之前必须关闭 10 个警报?!这让我想起了 90 年代后期的脚本儿童页面,这不是一个选择。
4. 大量其他延迟脚本:
大约有 10 个 jQuery 延迟或睡眠函数,其中一些实际上开发得非常巧妙,但没有一个起作用。一些原型选项,同样,我发现没有一个可以做到!十几个其他库和框架声称他们有我需要的东西,但可惜他们都合谋给了我虚假的希望。
我确信,由于内置模型对话可以停止执行,同时允许其他线程继续,因此必须有一些代码可访问的方式来做同样的事情而无需用户输入。
该代码实际上有成千上万行并且是专有的,所以我写了这个问题的小例子供您使用。请务必注意,您可以更改的唯一代码位于 onlyThingYouCanChange 函数中
测试文件:
<html>
<head>
</head>
</html>
<body>
<div id='iFrameHolder'></div>
<script type='text/javascript'>
function unChangeableFunction()
{
new_iFrame = onlyThingYouCanChange(document.getElementById('iFrameHolder'));
new_iFrame_doc = (new_iFrame.contentWindow || new_iFrame.contentDocument);
if(new_iFrame_doc.document)new_iFrame_doc=new_iFrame_doc.document;
new_iFrame_body = new_iFrame_doc.body;
if(new_iFrame_body.innerHTML != 'Loaded?')
{
//The world explodes!!!
alert('you just blew up the world! Way to go!');
}
else
{
alert('wow, you did it! Way to go!');
}
}
var iFrameLoaded = false;
function onlyThingYouCanChange(objectToAppendIFrameTo)
{
iFrameLoaded = false;
iframe=document.createElement('iframe');
iframe.onload = new Function('iFrameLoaded = true');
iframe.src = 'blank_frame.html'; //Must use an HTML doc on the server because there is a very specific DOM structure that must be maintained.
objectToAppendIFrameTo.appendChild(iframe);
var it = 0;
while(!iFrameLoaded) //I put the limit on here so you don't
{
//If I was able to put some sort of delay here that paused the exicution of the script, but did not halt all other browser threads, and did not require user interaction we'd be golden!
//alert('test'); //This would work if it did not require user interaction!
}
return iframe;
}
unChangeableFunction();
</script>
</body>
空白帧.html:
<html>
<head>
</head>
<body style='margin:0px'>Loaded?</body>
</html>
这是我结合响应者的想法得出的答案!你们真棒!
我被允许更改的函数的新来源:
function onlyThingYouCanChange(objectToAppendIFrameTo)
{
iFrameLoaded = false;
iframe=document.createElement('iframe');
iframe.onload = new Function('iFrameLoaded = true');
iframe.src = 'blank_frame.html'; //Must use an HTML doc on the server because there is a very specific DOM structure that must be maintained.
objectToAppendIFrameTo.appendChild(iframe);
var it = 0;
while(!iFrameLoaded) //I put the limit on here so you don't
{
if (window.XMLHttpRequest)
{
AJAX=new XMLHttpRequest();
}
else
{
AJAX=new ActiveXObject("Microsoft.XMLHTTP");
}
if (AJAX)
{
AJAX.open("GET", 'slow_page.php', false);
AJAX.send(null);
}
else
{
alert('something is wrong with AJAX!');
}
//If I was able to put some sort of delay here that paused the exicution of the script, but did not halt all other browser threads, and did not require user interaction we'd be golden!
//alert('test'); //This would work if it did not require user interaction!
}
return iframe;
}
slow_page.php :
<?
usleep(100000);//sleep for 1/10th of a second, to allow iFrame time to load without DOSing our own server!
?>
我确实想指出,我声明该函数之外没有什么可以更改的,并且添加 php 页面确实违反了该“规则”,但在可能的情况下我能够做到这一点。如果我不能这样做,我可以调用blank_frame.html而不是slow_page.php,并且它应该只需要调用一次(所以每帧加载2次)假设它以相同数量的响应iFrame 加载的时间。如果由于某种原因 iFrame 加载速度较慢,它可能会调用 2ce(总共 3 次调用服务器)