[Javascript] Хитрый onClick ссылки

2354570

Наткнулся на такую ситуацию.
Есть ссылка, открывающая окно, что-то типа
<a href="someurl" onClick="return handler;">x</a>
В обработчике onClick ссылки должно произойти следущее:
1. Надо создать Image.
2. Нужно запустить Image загружаться (назначить src) и выставить таймаут при помощи setTimeout.
3. Либо дождаться, пока картинка загрузится, либо дождаться сработавшего таймаута и выйти из обработчика.
То есть, для юзера эффект такой - он жмет ссылку, но она открывается с небольшим запаздыванием (время запаздывания - минимум время загрузки картинки, максимум таймаут в 5 секунд).
Так вот, непонятно, как реализовать вот это вот ожидание внутри самого обработчика onClick. Бесконечный цикл по переменной-флагу не вариант, конечно.
То есть получается как-то так, условно:


HTML:
<a href="something" onClick="return onClickHandler;">x</a>

.....

JS:


var leaveOnClickHandler = false;

function onClickHandler
{
var img = new Image;
img.onLoad = onLoadHandler;
img.src = 'someurl';

setTimeout('onLoadHandler', 5000);


//а тут что-то типа while(!leaveOnClickHandler) ;

return true;
}


function onLoadHandler
{
leaveOnClickHandler = true;
}


Как бы такое можно реализовать? Должно быть кроссбраузерное решение, ко всему прочему.

2354570

Да, кстати.
Конечно можно запоминать в обработчике onClick параметры нажимаемой ссылки - URL и target - и потом сэмулировать щелчок в onLoadHandler при помощи document.location или window.open, но это не совсем то.
К тому же, если у ссылки target="_blank", то при сработавшем позже window.open браузер может заблокировать новое окно как поп-ап.

PooH

на jQuery не хочешь?

PooH

без всяких ссылок

2354570

Не то, чтобы не хочу - не могу.
Нет гарантий, что jQuery будет подгружаться для каждой страницы, где это решение используется.

IvladV71

как реализовать вот это вот ожидание внутри самого обработчика onClick
зачем тебе это?

pilot

А зачем тебе один и тот же onloadhandler? Используешь одну функцию, потом мучаешься как отличить 2 случая.
Можно сделать так:
— Повесили на загрузку картинки обработчик onload,который по ссылке переходит
— settimeout функцию через 5 секунд перейти по ссылке
Какая раньше сработает, та и перейдет. Так?

Hastya

Это все довольно сложно реализовать.
http://lucassmith.name/2008/11/is-my-image-loaded.html

Vyacha

можно попробовать поизвращаться на тему:
 <a href="something" onClick="return onClickHandler(this);">x</a>

var freeClick = false;

function onClickHandler(a) {
if (freeClick) {
return !(freeClick = false);
}
var img = new Image;
img.onLoad = function { onLoadHandler(a); }
img.src = 'someurl';

setTimeout(function { onLoadHandler(a); }, 5000);
return false;
}

function onLoadHandler(a) {
freeClick = true;
a.click;
}

ещё хорошо бы таймаут чистить и отменять загрузку если не успел

Commandor

a.click;
Вот это место поподробнее.

Vyacha

Вот это место поподробнее.
да, действительно в ФФ не работает :(
в ФФ нельзя зафайрить нажатие на ссылку? :confused:

2354570

Если бы было можно надежно кликать ссылку программно - я бы не создал эту тему :smirk:
Более того, я бы забил на исходную задачу и уже давно бы сваял скрипт для скликивания ссылок контекстной рекламы. И, надо думать, не только я.
Очевидно, почему вообще клик ссылки не должен быть доступен из джаваскрипта, и я вообще удивлен, что где-то a.click может работать.

2354570

Можно сделать так:
— Повесили на загрузку картинки обработчик onload,который по ссылке переходит
— settimeout функцию через 5 секунд перейти по ссылке
Вообще говоря, задачу решили и тема неактуальна, но подискутировать можно.
Проблема, из-за которой я так упорно цеплялся за то, чтобы сам факт перехода по ссылке был результатом именно _сработавшего_ клика по ссылке (а не отмененного обработчиком клика и осуществленного позже обработчиком onload изобржания или функцией, вызванной по таймауту) появляется для ссылок с target="_new" или target="_blank".
Для таких ссылок нужно было бы открывать новое окно при помощи windows.open. В ФФ все попапы делятся на requested и unrequested. Попапы, открывающиеся в результате клика по ссылке - желательные, в том числе те, которые открываются по windows.open в обработчике клика. Остальные - то есть те, которые открываются по windows.open, вызванной, например, из функции, сработавшей по таймеру - ФФ считает нежелательными, по-умолчанию блокирует, и обойти это никак нельзя.
Именно поэтому я так упорно пытался все сделать в пределах обработчика, чтобы саму реакцию на клик ссылки - переход или открытие окна с переходом - осуществил сам браузер и не было проблем с блокировкой попапа.

pilot

Вообще говоря, задачу решили и тема неактуальна, но подискутировать можно.
А расскажи, пожалуйста, как.

2354570

Ну, на самом деле это все нужно было вот зачем.
В src картинки - ссылка на внутрикорпоративный веб-сервис статистики. В ответ он генерирует картинку 1х1. Обычно картинка добавляется при загрузке страницы, чтобы сервис зафиксировал просмотр страницы, но вот решили еще отслеживать просмотры недекорированных страниц (в которых этот js-файл не подгружается) и всякие там файлы для загрузки. А очевидный вариант в этом случае - фиксировать обращение в момент клика по ссылке.
Встал вопрос - как убедиться, что обращение к веб-сервису было (запрос ушел прежде чем переходить по ссылке? Если новая страница открывается в новом окне, то проблем нет - в старом окне картинка, вероятно, успеет подгрузиться. А если в текущем?
onreadystatechange для картинки не подошел - он фигово работает в ФФ. onload же будет ждать, пока картинка подгрузится - это надежно, но дольше, чем просто отправить запрос и забыть, да еще встала вот эта вот проблема с ожиданием и отложенной реакцией на клик браузером.
В итоге все оказалось очень просто.
Когда присваивается значение атрибуту src - браузер делает запрос сразу же. Я отслеживал запросы на стороне сервера, они приходят всегда, вне зависимости от того, как быстро потом произошел переход на новую страницу (т.е. даже если новая страница является соседней в локальной директории).
Я до этого не был уверен, что запрос будет послан всегда - например, что браузер не разорвет соединение, если переход на новую страницу уже был, а сервер с ответом затупил. Оказалось - дождется и картинку загрузит, даже если ответ вернулся через 10 секунд после перехода (лично для меня это было неожиданностью). А запрос так и подавно точно будет послан - так что необходимость чего-то ждать отпала, можно было просто разрешать переход по ссылке сразу после установки значения в src картинки.

2354570

Кстати, пока гуглил про всякое, нашел интересные статьи.
Одна про то, как реально устроены таймеры в однопоточном Javascript - http://ejohn.org/blog/how-javascript-timers-work/
Вторая про то, как открывать попапы - http://www.gtalbot.org/FirefoxSection/Popup/PopupAndFirefox....

Requested popups are windows created as a result of clicking a link or clicking a button. One mouse click, only one popup.
Unrequested popups are windows created automatically without any user interaction. Often, such unrequested popups have advertisement content. They often "pop up" as you arrive at a site or as you close a window. One mouse click, more than one popup.

Еще хорошая статья по специфике windows.open в ФФ есть здесь - http://developer.mozilla.org/en/DOM/window.open

pilot

По-моему логирование переходов по внешним ссылкам, скажем, у Гугла, сделано через редирект.
Это не кроссбраузерно?
Я уже забываю тонкости js, но вроде как можно на ссылку повесить обработчик, который при клике будет ее переписывать и соотв.отправлять запрос на сервер [Гугла], сервер уже редиректит в нормальное место.

2354570

Лог через редирект был вообще первым решением, но по ряду причин от него пришлось отказаться.

pilot

Я собственно про причины и спрашиваю, то что многие это делают через редирект — общее место, а вам-то почему не подошло?

2354570

Ок, что случится, если редиректящий сервис лежит?
В случае, если используется то решение, описанное выше, то, если сервер не отвечает - просто не загрузится картинка в фоне, но переход по нужному адресу будет.
Если же сервис лежит - то пользователь не попадет на нужную страницу, потому что не будет редиректа. Это плохо.

pilot

Ок, что случится, если редиректящий сервис лежит?
Это главная проблема? Если да, то она решается элементарно. Тем более у вас корпоративная сеть.
Весь этот "редиректящий сервис" — кусок конфига вебсервера, задача вашей системы в этом случае — парсить логи.
А для вебсерверов есть куча решений для обеспечения отказоустойчивости.

2354570

Как элементарно решается вопрос лежащего веб-сервера (именно самого сервера, а не приложения статистики стоящего не за балансировщиком нагрузки и без дублера?
И потом, да, я согласен, что вариант с редиректом - тоже хороший вариант, но мне неочевидно, что это решение прямо вот настолько лучше. Плюс само ожидание пользователем перехода на требуемую страницу потенциально дольше, если сервер статистики тупит с ответом.

pilot

Как элементарно решается вопрос лежащего веб-сервера (именно самого сервера, а не приложения статистики стоящего не за балансировщиком нагрузки и без дублера?
Дублером.
Плюс само ожидание пользователем перехода на требуемую страницу потенциально дольше, если сервер статистики тупит с ответом.

Там нечему тупить. Голый вебсервер отвечает.

2354570

Как элементарно решается вопрос лежащего веб-сервера .. стоящего не за балансировщиком нагрузки и без дублера?

Дублером.

:smirk:
Там нечему тупить. Голый вебсервер отвечает.

Да, это все чудесно, но - так и не последовало ответа, почему это решение принципиально лучше того с изображением, если у того:
а) быстрее осуществляется переход по ссылке - запаздывающий ответ сервера ввиду нагруженности никто не отменял
б) решение защищено от падения сервиса статистики
Аргумент "а вон гугл сделал так" - не аргумент, может у гугла есть возможность под обслуживание редиректов отдать 6 серверов с балансировщиком.

pilot

:smirk:
:smirk: Для резервирования, как это ни удивительно, достаточно всего 2 машины. Причем они могут быть еще чем-то заняты.
Да, это все чудесно, но - так и не последовало ответа, почему это решение принципиально лучше того с изображением

В твоем решении есть слабое место, "проверил вроде так и есть":
Когда присваивается значение атрибуту src - браузер делает запрос сразу же. Я отслеживал запросы на стороне сервера, они приходят всегда, вне зависимости от того, как быстро потом произошел переход на новую страницу (т.е. даже если новая страница является соседней в локальной директории).

Ну и кстати ты напрасно думаешь что я пытаюсь сказать что твое решение хуже. По-моему (плохо помню) и то и другое вроде много раз описывалось в инете, наверно тут нет большой проблемы.
Так что для меня вопрос исчерпан, спасибо.

2354570

Для резервирования, как это ни удивительно, достаточно всего 2 машины. Причем они могут быть еще чем-то заняты.
Ну, я с этим не спорю. Но не всегда же есть контроль над инфраструктурой.
Ладно, вопрос действительно исчерпан, оба решения подходят.
Оставить комментарий
Имя или ник:
Комментарий: