День добрый
Сегодня на Яндекс.Субботнике пытался поднять тему загрузки карт, но в силу своей социофобии и малого количества предварительных тестов, ничего хорошего из этого не получилось :) Сейчас постараюсь собрать все в кучку.
Предисловие :)
Есть сервис, на многих страницах которого расположены карты, как Google, так и Яндекса. Спорить на тему "у кого лучше" не будем - у всех свои плюсы и минусы. У кого детализированнее участок, который нужно визуализировать, тот и используется. Есть места, где мы сразу показываем карту, а есть и места, где карта отображается по щелчку пользователя на специальную ссылку. Чаще всего карта как раз не показывается и 80-90% пользователей в этом случае ссылку не нажмут.
С картами Google все просто: по щелчку на ссылку мы добавляем в документ скрипт, у которого есть параметр "callback", куда можно передать название функции, которая будет вызвана когда весь их js подгрузится и инициализируется.
У Яндекс.Карт такого параметра нет, зато есть ymaps.ready, куда можно передать callback-функцию с отрисовкой карты, когда ее использование станет возможным. Но для ее использования необходим загрузчик.
И так, проблема:
Загрузчик. Его надо добавлять на страницу всегда, когда карта может быть показана (в 80-90% не будет, см.выше). Скрипт весит 16 кб, срок жизни кеша на него - 5 минут (по крайней мере, на данный момент). Зачем его вешать на страницу, когда ни пользователю, ни Яндексу это не нужно?
Ну и, допустим, (внезапно) Яндекс ляжет, что, хоть и редко, но случается. Или на корпоративном прокси режутся Яндекс.Карты, чего только ни бывает в нашей странной жизни. В этом случае все плохо - пока подгрузка загрузчика не отвалится по таймауту, скрипты дальше выполняться не будут.
<!DOCTYPE html>
<html>
<body>
<!-- 16kb !-->
<!-- кеш на загрузчик истекает через 5 минут !-->
<script>
<!-- если api-maps.yandex.ru лежит, то прежде чем выполниться, этот кусок подождет пока
предыдущий скрипт отвалится по таймауту !-->
alert('lalala!');
</script>
</body>
</html>
[ с форматированием ]
(прописываем в /etc/hosts какой-нибудь левый ip-адрес для api-maps.yandex.ru и смотрим, когда вызовется alert)
Скачать загрузчик себе на сервер можно, но в таком случае однажды все сломается.
А вот попробуем по щелчку на ссылку подгрузить загрузчик. Хорошо звучит :)
<!DOCTYPE html>
<html>
<body>
<a href="#" id="mapLink">Покажи-ка мне карту!</a>
<div id="map" style="display: none; width: 500px; height: 300px">Извините, карта не получилась</div>
<script>
var
link = document.getElementById('mapLink'),
mapElement = document.getElementById('map'),
mapsInitialized = false;
function toggleMap() {
mapElement.style.display = 'block' === mapElement.style.display ? 'none' : 'block';
}
link.addEventListener('click', function(e) {
e.preventDefault();
if (mapsInitialized) {
toggleMap();
return;
} else {
var
script = document.createElement('script');
mapsInitialized = true;
script.onload = script.onreadystatechange = function(e, isAbort) {
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
script.onload = script.onreadystatechange = null;
if (!isAbort) {
// в IE6 (по-моему и в IE7 тоже) объект ymaps здесь уже существует
ymaps.ready(
// но вот эта функция не выполнится :[
function() {
var
yaCoords = [55.734, 37.58845];
mapElement.innerHTML = '';
toggleMap();
( new ymaps.Map(mapElement, {
'center': yaCoords,
'zoom': 16
} ) ).geoObjects.add(
new ymaps.Placemark(yaCoords)
);
}
);
}
}
};
document.body.appendChild(script);
}
}, false);
</script>
</body>
</html>
[ с форматированием ]
Сходу, когда столкнулись с проблемой, я попробовал сделать именно так. И все было ок, пока не попробовали сделать это в IE6 (и вроде даже в IE7). Callback в ymaps.ready не вызывается, тестировано сложной системой alert'ов :).
Состояние с IE сейчас проверить не могу - Parallels Desktop решил отказаться конвертировать тестовые образы от Microsoft со старыми IE. Но смогу в понедельник, если будет интересно :)
Вывод:
Callback в параметре к загрузчику - зло. Но позволит избавиться от многих неудобств разработчику.
Да и, верится мне, решить проблему можно и без лишнего параметра к загрузчику. Например, предопределенной заранее callback-функцией в какой-нибудь специальной переменной, на которую загрузчик посмотрит и выполнит, если найдет.
Надеюсь, никого не утомил. Буду рад диалогу, спасибо :)