Отложеная загрузка скриптов. Как быть с jQuery ?
Добрый день уважаемые. Вопрос к тем кто занимался вопросами оптимизации и пытается следовать рекомендации Google по вопросу - Удаления кода JavaScript и CSS, блокирующий отображение верхней части страницы . С CSS я худо-бедно разобрался, а вот как быть если необходимо что б первой всегда на страницу подгружалась библиотека с jQuery? Вот я нашёл такую рекомендацию
загружать jQuery по событию load function dlOnload() { var jq = document.createElement("script"), mainScript; jq.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"; document.body.appendChild(jq); jq.onload = function() { mainScript = document.createElement("script"); mainScript.src = "scripts/main.js"; document.body.appendChild(mainScript); } } window.addEventListener("load", dlOnload, false); а файлы зависимых от jQuery файлов после его загрузки. (Это вроди как main.js) Пока не удалось запустить данный скрипт. Да и как быть если этих дополнительных много... :cray: + если идет в середине php файла какой-то AJAX запрос и ему нужен jQuery |
Советую не заморачиваться с этим!
особенно если JQ как то влияет на формирование начальной видимой части (тоесть первые 1080px шапка и часть основного контента) это тоже рекомендация поисковиков |
Black_Star, у меня есть полностью рабочее решение:
Где-то в инете нашёл скрипт jQl и немного его поменял (уже не помню где и что именно менял): var jQl={q:[],dq:[],gs:[],ready:function(a){"function"==typeof a&&jQl.q.push(a);return jQl},getScript:function(a,c){jQl.gs.push([a,c])},unq:function(){for(var a=0;a<jQl.q.length;a++) $(document).ready(jQl.q[a]);jQl.q=[]},ungs:function(){for(var a=0;a<jQl.gs.length;a++)jQuery.getScript(jQl.gs[a][0],jQl.gs[a][1]);jQl.gs=[]},bId:null, boot:function(a){"undefined"==typeof window.jQuery.fn?jQl.bId||(jQl.bId=setInterval(function(){ jQl.boot(a)},25)):(jQl.bId&&clearInterval(jQl.bId),jQl.bId=0,jQl.unqjQdep(),jQl.ungs(),jQuery(jQl.unq()), "function"==typeof a&&a()) },booted:function(){return 0===jQl.bId},loadjQ:function(a,c){setTimeout(function(){var b=document.createElement("script");b.src=a;document.getElementsByTagName("head")[0].appendChild(b)},1);jQl.boot(c)},loadjQdep:function(a){jQl.loadxhr(a,jQl.qdep)},qdep:function(a){a&&("undefined"!==typeof window.jQuery.fn&&!jQl.dq.length?jQl.rs(a):jQl.dq.push(a))},unqjQdep:function(){if("undefined"==typeof window.jQuery.fn)setTimeout(jQl.unqjQdep,50);else{for(var a=0;a<jQl.dq.length;a++)jQl.rs(jQl.dq[a]); jQl.dq=[]}},rs:function(a){var c=document.createElement("script");document.getElementsByTagName("head")[0].appendChild(c);c.text=a},loadxhr:function(a,c){var b;b=jQl.getxo();b.onreadystatechange=function(){4!=b.readyState||200!=b.status||c(b.responseText,a)};try{b.open("GET",a,!0),b.send("")}catch(d){}},getxo:function(){var a=!1;try{a=new XMLHttpRequest}catch(c){for(var b=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],d=0;d<b.length;++d){try{a= new ActiveXObject(b[d])}catch(e){continue}break}}finally{return a}}};if("undefined"==typeof window.jQuery){var $=jQl.ready,jQuery=$;$.getScript=jQl.getScript}; Данный код создаёт 3 массива (для $(document).ready(), для $.getScript и для собственной ф-ии jQl.loadjQdep() - она асинхронно загружает внешний скрипт сразу, не дожидаясь когда загрузится jQuery (но выпонит его лишь после загрузки jQuery)). Вставляем этот код в head на каждой странице. Затем закидываем код jQuery и всё что от него зависит в один js файл, в самом конце кода вставляем строку: jQl.boot(); которая инициирует выполнение кода из массивов (фактически, просто вызывает эти же ф-ии в том же порядке, а поскольку они на этот момент уже переопределены кодом jQuery, то будут выполнены им, за исключением 3-го массива). Получившийся единый js-файл подгружаем асинхронно (обязательно _после_ кода jQl): <script async type="text/javascript" src="/js/combined.min.js?v1"></script> Соответственно, весь js-код на странице, который зависит от скриптов из combined.min.js надо обернуть в $(document).ready(function(){ ... }); либо в короткий вариант того же самого: $(function(){ ... }); Если же внешний файл, зависимый от jQuery нельзя поместить в общий js-файл (например он большой, но нужен не на всех страницах), то загружаем его через jQl.loadjQdep('/path/to/file.js'); Но для каждого такого скрипта надо соблюсти очерёдность исполнения inline-кода - для этого используем deffered: 1) В конце общего js-файла (но перед строкой jQl.boot();) определяем переменную-индикатор, например для скрипта lazyload: $lazyload = $.Deferred(); 2) В конце файла отдельного скрипта ставим резолв этой переменной: $lazyload.resolve(); 3) Весь inline-код на странице, зависимый от этого скрипта, помещаем в блок, который гарантирует что он выполнится только после резолва: $(function(){ $lazyload.done(function(){ ... }); }); P.S.: в процессе эксплуатации выяснилось, что в сафари событие DOMContentLoaded не запускает ф-ии, которые начали слушать это событие после того как оно уже сработало, поэтому иногда весь jQuery-зависимый inline-код не срабатывает (если общий файл с кодом jQuery загрузился после основной страницы). Для обхода этого добавили небольшой хак, и общее решение теперь выглядит так: В <head> каждой страницы такой код: <input id="workaround-DOMContentLoaded-event" type="hidden" value="0" /> <script> var jQl={q:[],dq:[],gs:[],ready:function(a){"function"==typeof a&&jQl.q.push(a);return jQl},getScript:function(a,c){jQl.gs.push([a,c])},unq:function(){for(var a=0;a<jQl.q.length;a++) $(document).ready(jQl.q[a]);jQl.q=[]},ungs:function(){for(var a=0;a<jQl.gs.length;a++)jQuery.getScript(jQl.gs[a][0],jQl.gs[a][1]);jQl.gs=[]},bId:null, boot:function(a){"undefined"==typeof window.jQuery.fn?jQl.bId||(jQl.bId=setInterval(function(){ jQl.boot(a)},25)):(jQl.bId&&clearInterval(jQl.bId),jQl.bId=0,jQl.unqjQdep(),jQl.ungs(),jQuery(jQl.unq()), "function"==typeof a&&a()) },booted:function(){return 0===jQl.bId},loadjQ:function(a,c){setTimeout(function(){var b=document.createElement("script");b.src=a;document.getElementsByTagName("head")[0].appendChild(b)},1);jQl.boot(c)},loadjQdep:function(a){jQl.loadxhr(a,jQl.qdep)},qdep:function(a){a&&("undefined"!==typeof window.jQuery.fn&&!jQl.dq.length?jQl.rs(a):jQl.dq.push(a))},unqjQdep:function(){if("undefined"==typeof window.jQuery.fn)setTimeout(jQl.unqjQdep,50);else{for(var a=0;a<jQl.dq.length;a++)jQl.rs(jQl.dq[a]); jQl.dq=[]}},rs:function(a){var c=document.createElement("script");document.getElementsByTagName("head")[0].appendChild(c);c.text=a},loadxhr:function(a,c){var b;b=jQl.getxo();b.onreadystatechange=function(){4!=b.readyState||200!=b.status||c(b.responseText,a)};try{b.open("GET",a,!0),b.send("")}catch(d){}},getxo:function(){var a=!1;try{a=new XMLHttpRequest}catch(c){for(var b=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],d=0;d<b.length;++d){try{a= new ActiveXObject(b[d])}catch(e){continue}break}}finally{return a}}};if("undefined"==typeof window.jQuery){var $=jQl.ready,jQuery=$;$.getScript=jQl.getScript}; document.addEventListener('DOMContentLoaded', function(){ var i = document.getElementById('workaround-DOMContentLoaded-event'); i.value = 1; i.click(); }); </script> <script async type="text/javascript" src="/js/combined.min.js?v1"></script> А в конце файла combined.min.js такой код: jQl.boot(); $('#workaround-DOMContentLoaded-event').on('click', function(){ if( this.value != 1 ) return; jQuery.ready(); $(this).remove(); }).trigger('click'); |
Цитата:
|
Цитата:
и он отработает после того как выполнятся оба условия: 1) браузер сформировал DOM страницы; 2) основной внешний скрипт с библиотекой jQuery загрузился и выполнился. P.S.: скорей всего бОльшая часть jQuery-зависимого кода у вас уже обёрнута таким образом, поэтому второй раз оборачивать не нужно. |
Часовой пояс GMT +3, время: 01:55. |