Есть функция JavaScript, код которой я не контролирую, и она вызывает функцию, которую я написал. Моя функция использует DOM для создания iFrame, определяет его src, а затем добавляет его к другому элементу DOM. Однако, прежде чем моя функция вернется и, таким образом, позволит продолжить выполнение содержащей ее функции, обязательно, чтобы iFrame был полностью загружен.
Вот что я пробовал и почему они не работают:
<сильный>1. Параметр SetTimeout:
в 99,999% случаев это САМЫЙ ответ. На самом деле, в последнее десятилетие, когда я был наставником в JavaScript, я всегда настаивал на том, что код всегда можно реорганизовать, чтобы использовать эту опцию, и никогда не верил, что существует сценарий, в котором это не так. Ну наконец-то я нашла! Проблема в том, что, поскольку моя функция вызывается встроенной, если самая следующая строка выполняется до того, как мой iFrame закончит загрузку, это полностью нейтрализует мой сценарий, и с момента завершения моего сценария внешний сценарий продолжается. Обратный вызов не будет работать
<сильный>2. Цикл «Ничего не делать»:
Этот вариант используется, пока (//iFrame не загружен){//ничего не делать}. Теоретически это не вернется, пока кадр не будет загружен. Проблема в том, что, поскольку это потребляет все ресурсы, iFrame никогда не загружается. Этот трюк, хотя и ужасно непрофессиональный, грязный и т. д., будет работать, когда вам просто нужна встроенная задержка, но, поскольку мне требуется внешний поток для завершения, он не будет работать.
В FF через несколько секунд он приостанавливает выполнение скрипта и всплывает предупреждение о том, что существует не отвечающий скрипт. Пока это оповещение активировано, iFrame может загружаться, а затем моя функция может вернуться, но зависание браузера на 10 секунд, а затем требование от пользователя правильно отклонить ошибку - недопустимо.
<сильный>3. Диалог модели:
Меня вдохновил тот факт, что всплывающее окно FF позволяет загружать iFrame, останавливая выполнение функции, и, подумав об этом, я понял, что это потому, что модальный диалог способ остановить выполнение, но позволяя другим потокам продолжаться! Великолепно, поэтому я решил попробовать другие модальные варианты. Такие вещи, как alert(), прекрасно работают! Когда он всплывает, даже если только на 1/10 секунды, iFrame может завершиться, и все отлично работает. И на случай, если 1/10 секунды будет недостаточно, я могу поместить диалог модели в цикл while из решения 2, и это обеспечит своевременную загрузку 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;
}
медленная_страница.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 обращения к серверу)
new Function(){ return code; }
с обратным вызовомsetTimeout
? - person meder omuraliev   schedule 02.01.2011