Клуб API Карт

Загрузка карт [решено]

Пост в архиве.

День добрый

 

Сегодня на Яндекс.Субботнике пытался поднять тему загрузки карт, но в силу своей социофобии и малого количества предварительных тестов, ничего хорошего из этого не получилось :) Сейчас постараюсь собрать все в кучку.

 

Предисловие :)

Есть сервис, на многих страницах которого расположены карты, как Google, так и Яндекса. Спорить на тему "у кого лучше" не будем - у всех свои плюсы и минусы. У кого детализированнее участок, который нужно визуализировать, тот и используется. Есть места, где мы сразу показываем карту, а есть и места, где карта отображается по щелчку пользователя на специальную ссылку. Чаще всего карта как раз не показывается и 80-90% пользователей в этом случае ссылку не нажмут.

С картами Google все просто: по щелчку на ссылку мы добавляем в документ скрипт, у которого есть параметр "callback", куда можно передать название функции, которая будет вызвана когда весь их js подгрузится и инициализируется.

У Яндекс.Карт такого параметра нет, зато есть ymaps.ready, куда можно передать callback-функцию с отрисовкой карты, когда ее использование станет возможным. Но для ее использования необходим загрузчик.

 

И так, проблема:

Загрузчик. Его надо добавлять на страницу всегда, когда карта может быть показана (в 80-90% не будет, см.выше). Скрипт весит 16 кб, срок жизни кеша на него - 5 минут (по крайней мере, на данный момент). Зачем его вешать на страницу, когда ни пользователю, ни Яндексу это не нужно?

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

<!DOCTYPE html>
<html>
<body>
    <!-- 16kb !-->
    <!-- кеш на загрузчик истекает через 5 минут !-->
    <script src="http://api-maps.yandex.ru/2.0/?lang=ru-RU"></script>
    <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.setAttribute('src', 'http://api-maps.yandex.ru/2.0/?lang=ru-RU&load=package.full');
                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-функцией в какой-нибудь специальной переменной, на которую загрузчик посмотрит и выполнит, если найдет.

 

Надеюсь, никого не утомил. Буду рад диалогу, спасибо :)

5 комментариев

в загрузчике есть callback

if (!(window.ymaps))

    {

        var self = this,

            initFunc = '_mapOnLoad'+Math.round(Math.random()*1000);

 

        window[initFunc] = function() {

         initMap();

        };

        $.getScript("http://api-maps.yandex.ru/2.0/?load=package.standard"+

/*            "&mode=debug"+*/

            "&lang=ru-RU&onload="+encodeURIComponent(initFunc));

    }

Игорь Калашников
28 января 2016, 04:03

Debug mode интересный, спасибо. И onload работает, а я тут простыню целую понаписал :)

Спасибо большое за ответ.

Написали бы про onload в документации. Наверняка, не мне одному было бы полезно.

Игорь Калашников
28 января 2016, 04:03

кошмар сколько копипаста вверху загрузчика :) мог бы и не 16 кб весить

попробуйте замениь весь копипаст, а потом провести через gzip
вы будете удивлены
Игорь Калашников
28 января 2016, 04:03

Ясен перец что одним уничтожением копипаста существенно размер загрузчика не уменьшить, ~100 байт - не велика цена. Зато глазу приятнее.

Ну и все равно можно меньше сделать :)