Javascript и объект IMG = глюки
Есть программка, которая показывает картинки, точнее должна показывать картанки. Но делает она это не совсем правильно, а точнее, только со второго запуска. Вот что происходит:
Я написал функцию, проверяющую img.readystate и выходящую из самой себя когда "complete", выдавая алерт "done"
Попутно внедрил отладочный счетчик самовызовов функции. Кроме того, поставил печатать img.readystate после вызова функции.
Происходит совершенно загадочная вещь: при первом запуске этого скрипта происходит следующее: сначала выскакивает алерт "done", потом печатается undefined 1 и... все, белый экран, то есть картинки нет.
Закрываем окно браузера и снова запускаем этот файл. Наблюдается следущее: тут-же то есть мгновенно получаем алерт "done", печатется complete 0, потом показывается картинка.
Говорим "хорошо" и жмем reftesh. Наблюдается следущее: тут-же то есть мгновенно печатается - undefined 1, потом показывается картинка, а уж после всего этого - алерт done. Я не пойму - как это получается? Ведь функция checkPicture вызывается ДО ТОГО, как происходит выполнение document.write?
Причем, самое интересное, что если жать refresh несколько раз, то примерно с вероятностью 1:5 получаем вариант 2, то есть сначала алерт, потом надпись complete 0 и картинку.
Вот текст файла, над которым и проводились опыты.
Может кто поможет мне сделать то-же самое, но как-нибудь по другому? Или поправить что-то?
<HTML><HEAD><TITLE>picture show</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function calculate() {
if (document.images)
{
img = new Image();
img.src = "../images/picture.jpg" ;
}
if (document.all) h = document.body.clientHeight - 60;
else if (document.layers) h = window.innerHeight - 60;
else h = 640;
if (document.all) w_doc = document.body.clientWidth;
else if (document.layers) w_doc = window.innerWidth;
else w_doc = 640;
w = h * img.width / img.height;
if (w > w_doc) w = (w_doc - 20);
if (w > img.width) w = img.width;
return (w);
}
function checkPicture() {
if (img.readyState == 'complete') {
alert('Done');
rrr = img.readyState
return (rrr);
}
setTimeout('checkPicture()',100);
b = b + 1;
}
//-->
</script>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript"><!--
w = calculate();
b = 0;
a = 0;
a = checkPicture();
document.write (a, b);
document.write('<img src = "' + img.src + '" width="' + w + '" border="0">');
//-->
</script>
</BODY></HTML>
Ты бы пояснил задачку подробнее. Как я понял ты хочешь что бы картинки показывались только после того, как загрузятся целиком?
Не совсем так... я хотел бы, чтобы картинки ПОКАЗЫВАЛИСЬ с первого раза. А тут получается, что с первого запуска - чичтый экран. Я закрываю окно, запускаю еще раз - все нормально! В чем грабли - не пойму!
А кстати у меня картинки показываются с первого раза. Так если тебе просто нужно показать картинку, то зачем такие сложные манипуляции?
попробуй подсунь картинку пожирнее... типа 1600х1200 и размерчиком под 2 мегабайта и посмотри еще разок, что получится.
PS: нафига народ извращается, непонятно....
Но зато я заметил там интересные вещи, которые вобще не понятно зачем сделаны:
функцию calculate() пропускаем - там ничего страшного нету.
А дальше смотрим вместе, так сказать, по-шагово:
1 function checkPicture() {
2 if (img.readyState == 'complete') {
3 alert('Done');
4 rrr = img.readyState
5 return (rrr);
6 }
7 setTimeout('checkPicture()',100);
8 b = b + 1;
9 }
И что мы видим???
- если картинка большая, то на строчке 2 условие не срабатывает (следовательно alert тоже) и мы попадаем на строчку 7.
В 7-ой строке мы устанавливаем таймаут, увеличиваем b и ВЫХОДИМ ничего не возвращая. Таким образом, у нас a = НЕПОНЯТЬ_ЧТО, b=1 и вся эта фигня печатается в документ вместе с тэгом img - картинка грузится и выводится.
Но мы не забыли про то, что у нас в таймауте висит функция, поэтому по истечении 100мсек. она опять вызывается, есесно, картинка уже подгрузилась, поэтому на строчке 7 условие срабатывает - мы видим alert и функция возвращает "compleat" НЕПОНЯТЬ_КУДА.
Ну а при F5 всякие описанные тобой, катаклизмы получаются из-за кэширования катринок. Поэтому иногда у тебя картинка загружается сразу и всё ОК, а иногда всё так, как описано выше.
document.write (a, b);
Это как, сначала в a пишется значение из функции checkPicture - естественно неизвестно какое, т.к. при первом старте функции картинка еще не загружена. Затем, без всяких проверок a на истину (в теории функция вернет истину при загрузке картинки) в документ пишется НЕОПРЕДЕЛЕННОЕ а и количество проверок, которое на момент записи равно 1 или 0, если картинка успела загрузиться до обращения к функции (при использовании кэша). Дальше идет строка:
img.src - это путь к картинке, т.е. таким макаром картинка может быть загружена и без всяких функций.
По идее, можно зациклить вызов checkPicture, пока она не вернет истину, но это повесит эксплорер. Я бы написал что-то вроде этого:
<HTML><HEAD><TITLE>picture show</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
b = 0;
function calculate() {
if (document.images)
{
img = new Image();
img.src = "../images/picture.jpg" ;
}
if (document.all) h = document.body.clientHeight - 60;
else if (document.layers) h = window.innerHeight - 60;
else h = 640;
if (document.all) w_doc = document.body.clientWidth;
else if (document.layers) w_doc = window.innerWidth;
else w_doc = 640;
w = h * img.width / img.height;
if (w > w_doc) w = (w_doc - 20);
if (w > img.width) w = img.width;
}
function checkPicture()
{
if(document.all("ds") != "undefined")
{
if (img.readyState == 'complete')
{
ds.innerHTML = '<img src = "' + img.src + '" width="' + w + '" border="0">';
alert('Done');
return;
}
b = b + 1;
if(b > 120)
{
ds.innerText = "Timeout exceeded.";
return;
}
ds.innerText = 'Overhead sent at ' + b + ' sec. before...';
setTimeout("checkPicture()", 1000);
return;
}
setTimeout("checkPicture()", 1000);
return;
}
//-->
</script>
</HEAD>
<BODY onLoad="calculate();checkPicture();">
<TABLE CELLPADDING = "1" BORDER = "1"><TR><TD>Image preloading.</TD></TR><TR><TD>
<DIV ID="ds"></DIV>
</TD></TR></TABLE>
</BODY></HTML>
Это как, сначала в a пишется значение из функции checkPicture - естественно неизвестно какое, т.к. при первом старте функции картинка еще не загружена. Затем, без всяких проверок a на истину (в теории функция вернет истину при загрузке картинки) в документ пишется НЕОПРЕДЕЛЕННОЕ а и количество проверок, которое на момент записи равно 1 или 0, если картинка успела загрузиться до обращения к функции (при использовании кэша).
дык это я просто понавтыкал, чтобы видеть то, что происходит в скрипте. Может не очень грамотно понавтыкал, но тут уж как получилось :-))) В конечной версии никаких печатей и алертов просто не будет.
img.src - это путь к картинке, т.е. таким макаром картинка может быть загружена и без всяких функций.
естественно, только эти картинки не успевают...
По идее, можно зациклить вызов checkPicture, пока она не вернет истину, но это повесит эксплорер. Я бы написал что-то вроде этого:
<HTML><HEAD><TITLE>picture show</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
skip
Блин! не работает. Я уж подумал на свою систему (w2k + 6ie) но вот щас прошелся по другим и все то-же самое. Проверял на w98+5ie, wme+6ie и w98+6ie. все один в один. Вот смотри, я приложил картиночку, вверху - то, что получается после первого запуска. Внизу - после второго запуска файла.
Если ставлю на Automatic, то картинка отображается сразу после загрузки.
Работает, работает. Что выбрано у тебя в настройке Check for newer versions of stored pages? Прикол-то весь в этом самом кэше. Когда я ставлю на Never, картинка начинает грузиться из и-нета при записи в документ:
Если ставлю на Automatic, то картинка отображается сразу после загрузки.
У меня этих картинок - навалом! Просто девать некуда :-) Поэтому я ПЕРЕД КАЖДЫМ ЗАПУСКОМ меняю номер картинки на следующий по порядку.
Следуя твоему совету, провел эксперимент: 3 запуска, каждый раз с новыми картинками, и с параметрами кеша:
1) при каждом посещении
2) автоматически
3) никогда
Ты будешь смеяться, но результат ПОЛНОСТЬЮ совпадает с тем, что я писал в предыдущем письме и полностью совпадает с картинкой, которую я присылал. :-((((
Я плакаль :-(
У меня этих картинок - навалом! Просто девать некуда :-) Поэтому я ПЕРЕД КАЖДЫМ ЗАПУСКОМ меняю номер картинки на следующий по порядку.
Следуя твоему совету, провел эксперимент: 3 запуска, каждый раз с новыми картинками, и с параметрами кеша:
1) при каждом посещении
2) автоматически
3) никогда
Ты будешь смеяться, но результат ПОЛНОСТЬЮ совпадает с тем, что я писал в предыдущем письме и полностью совпадает с картинкой, которую я присылал. :-((((
Я плакаль :-(
Использовал explorer 5.00 - все работает идеально. Картинка отображается сразу с сообщением Done!
Настройки Settings у меня такие:
ага, ну так я говорю - ставил и то и другое... и третье.
И на четырех компах пробовал.
Попробуй подсунь картинку пожирнее... типа 1600х1200 или побольше, да и размерчиком под 2-3 мегабайта и посмотри еще разок, что получится.
Я уже месяца 3 бьюсь, чего только не перепробовал - проблема остается. И систему за это время переставлял, все равно не помогает. Книгу, блин, купил тоооолстючую про JavaScript - нифига!
Вот и думаю....
Давай попробуем так - вот смотри, самый первый вариант, безо всяких там функций и таймаутов. Попробуй, что будет? Покажет с первого раза?
<HTML><HEAD>
<TITLE>pic</TITLE>
</HEAD>
<BODY bgcolor="#CCCCCC" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000" >
<CENTER>
<SCRIPT LANGUAGE="JavaScript"><!--
if (document.images)
{
img = new Image();
img.src = "../images/picture001.jpg" ;
}
if (document.all) h = document.body.clientHeight - 60;
else if (document.layers) h = window.innerHeight - 60;
else h = 640;
if (document.all) w_doc = document.body.clientWidth;
else if (document.layers) w_doc = window.innerWidth;
else w_doc = 640;
w = h * img.width / img.height;
if (w > w_doc) w = (w_doc - 20);
if (w > img.width) w = img.width;
document.write('');
//-->
</script>
</center></BODY></HTML>
function calculate() {
if (document.images)
{
img = new Image();
img.src = "http://foto.yarnet.ru/photo/animals/photo_13.jpg" ;
}
if (document.all) h = document.body.clientHeight - 60;
else if (document.layers) h = window.innerHeight - 60;
else h = 640;
if (document.all) w_doc = document.body.clientWidth;
else if (document.layers) w_doc = window.innerWidth;
else w_doc = 640;
w = h * img.width / img.height;
if (w > w_doc) w = (w_doc - 20);
if (w > img.width) w = img.width;
Получается, что вычисление w начинается при НЕЗАГРУЖЕННОЙ картинке, т.е. данные о ширине и высоте НЕОПРЕДЕЛЕНЫ!!! Дальше ты пишешь:
И получаешь в параметре width чушь! На самом деле картинка загрузится, но ее ширина будет 0, поэтому ты видишь в таблице на месте картинки какую-то точку. При перезагрузке старницы эта картинка на момент расчета w будет существовать в кэше и все отобразится правильно.
Получается, что вычисление w начинается при НЕЗАГРУЖЕННОЙ картинке, т.е. данные о ширине и высоте НЕОПРЕДЕЛЕНЫ!!!
И получаешь в параметре width чушь! На самом деле картинка загрузится, но ее ширина будет 0, поэтому ты видишь в таблице на месте картинки какую-то точку. При перезагрузке старницы эта картинка на момент расчета w будет существовать в кэше и все отобразится правильно.
Золотые слова! Я до такого-же точно расклада дошел только через месяц наверное! вот что значит профессионал!
Вот теперь пытаюсь затормозить вычисление w до полной загрузки картинки... для того и весь этот геморрой, но нифига не выходит. Помоги, а?
<HTML><HEAD><TITLE>picture show</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
b = 0;
h = 0;
w_doc = 0;
function calculate() {
if (document.images)
{
img = new Image();
img.src = "../images/picture.jpg" ;
}
if (document.all) h = document.body.clientHeight - 60;
else if (document.layers) h = window.innerHeight - 60;
else h = 640;
if (document.all) w_doc = document.body.clientWidth;
else if (document.layers) w_doc = window.innerWidth;
else w_doc = 640;
}
function checkPicture()
{
if(document.all("ds") != "undefined")
{
if (img.readyState == 'complete')
{
w = h * img.width / img.height;
if (w > w_doc) w = (w_doc - 20);
if (w > img.width) w = img.width;
ds.innerHTML = '<img name = "img1" width="' + w + '" border="0">';
document.images['img1'].src = img.src;
alert('Done');
return;
}
b = b + 1;
if(b > 120)
{
ds.innerText = "Timeout exceeded.";
return;
}
ds.innerText = 'Overhead sent at ' + b + ' sec. before...';
setTimeout("checkPicture()", 1000);
return;
}
setTimeout("checkPicture()", 1000);
return;
}
//-->
</script>
</HEAD>
<BODY onLoad="calculate();checkPicture();">
<TABLE CELLPADDING = "1" BORDER = "1"><TR><TD>Image preloading.</TD></TR><TR><TD>
<DIV ID="ds"></DIV>
</TD></TR></TABLE>
</BODY></HTML>