Асинхронная загрузка виджетов ВКонтакте

Как известно, ВКонтакте есть несколько полезных виджетов, которые можно разместить на своем сайте, например, виджет группы или комментариев. Но есть у них недостаток: они вставляются обычным тегом script и подгружаются сервера ВКонтакте, что ощутимо тормозит загрузку сайта целиком, а если вдруг у пользователя по каким-то причинам заблокирован домен vk.com, то он может и вообще не дождаться загрузки сайта. В результате я решил сделать загрузку асинхронной. Первое, что пришло в голову — это использовать свойство defer у тега script, но оказалось, что в этом случае ничего не работает вообще. В результате поступил иначе:
повесил на событие DOMContentLoaded обработчик, который добавляет тег script уже после того, как основная DOM-модель сформирована и текстовая часть сайта отобразилась у пользователя (наверное, лучше было бы использовать и событие onload, но у меня почему-то иногда "застревает" счетчик Яндекс-Метрики, поэтому onload не наступает). Делалось это с помощью функции appendChild. Однако тут возникла другая проблема: выход из функции происходил сразу, не дожидаясь полной загрузки скрипта. В результате попытки вызвать функции объекта VK сразу после appendChild приводили к ошибкам, так как он еще не был инициализирован. Эта проблема решилась с помощью добавления обработчика на событие onload у созданного тега script.

В итоге получается примерно такой код:


<script type="text/javascript">
  var VK_loader = function() { // загрузчик, который вызывается по событию DOMContentLoaded и добавляет тег script
      var oHead = document.getElementsByTagName("head")[0];
      var oScript= document.createElement("script");
      oScript.type = "text/javascript";
      oScript.async = true;
      oScript.src="http://userapi.com/js/api/openapi.js?20";
      oHead.appendChild(oScript);        
      oScript.onload = function() { // а это обработчик, который вызывается тогда, когда скрипт ВКонтакте уже загрузился
// Тут инициализируем API ВКонтакте и помещаем код виджетов
        VK.init({apiId: ID_сайта_ВКонтакте, onlyWidgets: true});
        VK.Widgets.Group("vk_groups", {mode: 0, width: 200, height: 250}, номер_группы); // вывод группы
        VK.Widgets.Comments("vk_comments", {limit: 10, width: 400, attach: "*"}); // вывод комментариев
      }
   };
   if ( document.addEventListener ) { // вешаем событие для обычных броузеров
    document.addEventListener("DOMContentLoaded", function(){
// когда событие происходит, удаляем обработчик и вызываем загрузчик
    document.removeEventListener("DOMContentLoaded", arguments.callee, false);
      VK_loader();
    }, false );
  } else if ( document.attachEvent ) {
// вешаем событие для IE. Он (до 9 версии) не поддерживает DOMContentLoaded, вместо этого используем событие readystatechange
    document.attachEvent("onreadystatechange", function(){
    if ( document.readyState === "complete" ) {
    document.detachEvent( "onreadystatechange", arguments.callee );
    VK_loader();
    }
    });
  }
</script>

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

Добавлено 19 мая 2018 года. А с помощью библиотеки CondiLoader все получается гораздо проще, и при этом полностью асинхронно:


<script> function CondiLoaderInit() {  new CondiLoader([ {   js: "http://userapi.com/js/api/openapi.js?20",    init: function () {         VK.init({apiId: ID_сайта_ВКонтакте, onlyWidgets: true});         VK.Widgets.Group("vk_groups", {mode: 0, width: 200, height: 250}, номер_группы); // вывод группы         VK.Widgets.Comments("vk_comments", {limit: 10, width: 400, attach: "*"}); // вывод комментариев    } }  ],{ /* options */ }); } </script> <script src="condi_loader.js" onload="CondiLoaderInit()" defer="defer"></script>