1. Воспользоваться возможностями HTML и «добавить» в новый элемент с тегом script:
document.write('<script type="text/javascript" src="myScript.js"></script>');
… или…
var loadedJS = document.createElement('script');
loadedJS.src = "myScript.js";
loadedJS.type = "text/javascript";
loadedJS.language = "javascript";
var head = document.getElementsByTagName('head')[0];
head.appendChild(loadedJS);
… или…
var head = document.getElementsByTagName('head')[0];
head.innerHTML+= '<script type="text/javascript" src="myScript.js"></script>';
2. Воспользоваться <iframe src=«loadJS.html#myScript.js», внутри которого уже подгрузим JS в зависимости от хэша и выполним его.
3. Воспользоваться AJAX.
Этот способ меня и заинтересовал в свое время. В чем его преимущество? В том, что скрипт можно подгрузить в любом месте выполнения программы на JS и он гарантированно выполнится до того, как интерпретатор перейдет к обработке следующей команды.
Создадим объект js с одним свойством «root», обозначающим путь к папке со скриптами:
js= {root : ''};
После этого добавим объекту свойство — modules, являющееся объектом, хранящим состояния подгруженных скриптов:
js.modules = {};
Теперь опишем функцию самой подгрузки скрипта и выполнения его:
js.include= function(_path) {
// На тот случай, если файл в подпапке
var _id= _path.replace(/\//g, '');
// Если скрипт уже подгружен, выходим
if (js.modules[_id]) return;
// Открываем доступ через AJAX
var reader = new XMLHttpRequest();
// Настраиваем синхронный метод подгрузки
reader.open('GET', js.root+_path+'.js', false);
// Отсылаем запрос на получение файла
reader.send(null);
// Запоминаем исходный код файла
var sourceCode= reader.responseText;
// Устанавливаем флаг "загружен" для соответствующего модуля
js.loaded(_id);
// Выполняем подгруженный код
eval(sourceCode);
}
Так же допишем функцию «loaded»:
js.loaded= function(_id) {
js.modules[_id]= true;
}
Теперь в любом месте программы можно вызвать
js.include('myScript.js');
и скрипт выполнится, при этом программа подождет выполнения вашего скрипта, и только потом продолжит выполнение.
Благодаря «массиву» loaded скрипты, при циклической зависимости не будут «вешать» систему, так как каждый скрипт выполнится лишь единожды за время жизни страницы.
Также вы можете прописать js.loaded() в любом файле, который подгружаете через , чтобы он не выполнялся через include.
Это на тот случай, если требуется сделать подгрузчик скриптов «по-быстрому». Также можно воспользоваться библиотекой «RequireJS», выполняющей те же действия.
Если результат выполнения скрипта вам не нужен прямо сейчас, то загрузку можно выполнить в асинхронном режиме, и страница не будет ожидать, пока выполнится ваш файл, а продолжит выполнение следующих команд. Ваш файл выполнится сразу, как только загрузится. Сама функция include() будет выглядеть след. образом:
js.include= function(_path) {
// На тот случай, если файл в подпапке
var _id= _path.replace(/\//g, '');
// Если скрипт уже подгружен, выходим
if (js.modules[_id]) return;
// Открываем доступ через AJAX
var reader = new XMLHttpRequest();
// Настраиваем асинхронный метод подгрузки
reader.open('GET', js.root+_path+'.js');
// объявляем функцию после загрузки
reader.onreadystatechange = function ()
{
// проверяем на готовность
if(reader.readyState == 4)
{
// обрабатываем
var sourceCode= reader.responseText;
eval(sourceCode);
// Устанавливаем флаг "загружен" для соответствующего модуля
js.loaded(_id);
}
}
// Отсылаем запрос на получение файла
reader.send(null);
}
Комментарии (36)
bertmsk
02.09.2015 11:49+2Вообще динамическая подгрузка скриптов (именно скриптов, а не данных JSON) говорит об ужасной архитектуре системы.
Обычно скрипты компонуются в 1 файл и «сжимаются» кложурой.Aingis
02.09.2015 12:31Вполне годный способ — грузить сначала нужное для критического пути, а потом всё остальное. Например, зачем вам всегда грузить скрипты для формы обратной связи, если ими пользуются лишь считанные проценты пользователей? Другое дело, что вопрос модульной загрузки разработан вдоль и поперёк.
Delphinum
02.09.2015 13:02-1А если по ограничениям безопасности, применяемым в компании, нельзя загружать некоторый скрипт до определенного условия?
Nadoedalo
02.09.2015 16:54Серьёзно? У кого-то например ~100 КБ минифицированных и gzip-нутых исходников. Это не считая файлов переводов, шаблонов и css(ещё каждый примерно столько же). Итого пол-метра получится не считая библиотек и данных. Это если всё сразу тащить получится что сайт откроется примерно никогда, потому что @#%$ пользователь ваш сайт который открывается 5+ секунд. А на данный момент чё-то происходит на экране уже через 250 мс, а потом данные плавно подгружаются в течении 2-3 секунд после.
XanderBass
02.09.2015 12:58Ещё один случай, когда хочется ткнуть в проект «Грёбаный сайт». Вы всерьёз предлагаете..? Ну в общем выше написали уже этот вопрос про загрузку. Прелесть обычной компоновки тегами в том, что оная не вешает наглухо страницу во время подгрузки содержимого. К тому же остаётся актуальным самый простой вопрос: зачем? Где можно применять такую методику вообще? Если у меня к примеру странички генерируются при помощи того же PHP, задачу по отбору скриптов для подгрузки я возложу на шаблонизатор (теги script). Для фронтенда веб-приложения необходимые библиотеки так и так должны подгружаться. Так что тут опять теги. Форма обратной связи, если есть — тег в чанке формы.
lair
02.09.2015 13:00Где можно применять такую методику вообще?
Конкретно авторскую — нигде. А вообще модульную загрузку — в сложных страницах, когда не вся функциональность нужна сразу (а иногда не нужна вообще). Проблема с тегами в том, что они грузят скрипты всегда, а зачем нам это счастье?
oWeRQ
02.09.2015 16:26Если хочется велосипед, почему бы не сделать его хотя бы с круглыми колесами, как-то так:
function loadScript(src, onload) { var head = document.head || document.querySelector('head') || document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.async = true; script.type = 'text/javascript'; script.src = src; script.onload = onload; head.appendChild(script); }
Или можно просто воспользоватьсяjQuery.getScript
.Dobby007
02.09.2015 19:09jQuery.getScript. не гарантирует выполнение функции success после выполнения загружаемого скрипта — она может выполниться еще до этого. Они так и пишут в документации: «The callback is fired once the script has been loaded but not necessarily executed.»
oWeRQ
02.09.2015 19:52Спасибо за уточнение, надо будет посмотреть реализацию в jQuery, вероятно тому же подвержена приведенная выше loadScript, но оно должно быть решено в shim в requirejs.
Dobby007
02.09.2015 22:27Там все очень-очень хитро… Можете тут почитать про порядок выполнения скриптов: https://hsivonen.fi/script-execution/
mwizard
02.09.2015 19:36+1Вместо выдумывания велосипедов, обратите взор к стандарту.
Для загрузки на этапе компоновки (синхронной с точки зрения скрипта, асинхронной с точки зрения платформы):import Foobar from './foobar'; import { LolWutService, LolWutIntf } from './services/lolwut'; import * from './oh-you';
Для динамической загрузки (в зависимости от стандарта, который примут):try { let module1 = await System.import("./foobar", { ...options }); let module2 = await Reflect.Loader.import("./foobar", { ...options }); } catch(e) { // import error! }
System.import
возвращаетPromise
, с которым потом можно делать, что угодно — например,await
-нуть.
Реализация первого способа — babel. Реализация второго — es6-module-loader или systemjs.
ko11ega
02.09.2015 23:56-1А еще можно вот так:
import 'package:deferred/hello.dart' deferred as hello; greet() async { await hello.loadLibrary(); hello.printGreeting(); }
Не дожидаясь стандартов которые когда-нибудь примут, не изобретая собственных велосипедов, не используя сторонних библиотек. Уже год как можно, причем какой бы стандарт не приняли, код менять не придется…
Но это на Dart, с трансляцией в JavaScript, а Dart ведь не нужен, так?
Google обязательно его забросит как и другие свои проекты…
Dart on mobile is incredibly exciting. Mobile has eaten the world, we think Dart is a great fit there. And don't forget, Dart is used by Ads engineers every day to build next-gen systems.?
Seth Laddmwizard
03.09.2015 01:55Dart ведь не нужен, так?
Ну, вообще да, так. Dart можно смело выбрасывать — это мертворожденная поделка без единого способа испооьзовать его на практике. Конечно, для академических целей оно может и то, что нужно, но для практических задач существуют ES6 и ES7 :)ko11ega
04.09.2015 02:18Вам конечно виднее, как оно там в вашей версии реальности.
Напомню просто
Один пацан писал все на JavaScript, и клиент, и сервер, говорил что нравится, удобно, читабельно. Потом его в дурку забрали, конечно
Я к тому, что эта шутка была популярна и уместна несколько лет назад и аргументация в ней, как и в ваших заявлениях про Dart, отсутствует начисто, а эффект ее применения основывался на нечастом использовании fullstack Javascript на тот момент и на ярких эмоциональных манипуляциях. :)
А если пройтись по фактам, то можно понять как работает психика людей с стокгольмским синдромом. Если на протяжении многих лет учишься «взлетать из болота размахивая костылями» и гробишь на это кучу времени и нервных клеток, то защитные механизмы психики будут защищать и рационализировать эти вынужденные инвестиции.
Не вы были вынуждены программировать на корявом языке с проблемной отладкой при помощи набора разнообразных хаков из-за того что его просто поддерживает каждый браузер, а JavaScript замечательный язык на котором можно писать и Enterprise решения, вот дождемся ES7 и все будет совсем хорошо.
Теперь касательно фактов конкретно вашего персонально недопонимания того как можно использовать Dart на практике и зачем. Ниже будут примеры ребят которые понимают, используют и зарабатывают при помощи софта написанного на Dart.
Там и картинки красивые есть, без лишнего академизма.
Софт для визуальной настройки InternetOfThings, умный дом по нашему. А вот видео где они рассказывают как у них это сделано и что им дал Dart.
Вот пример забавной игры.
А вот пример того как с Node.js пересели на Dart и ради чего.
Ну и написал я это конечно же не для того чтобы конкретно вас в чем то переубедить, а чтобы у тех «начинающих» кто дорос до того, что в его веб-проектах возникают вопросы важности отложенной загрузки кода(как думаете сколько строк кода д.б. в проекте что был смысл делать отложенную загрузку его частей и какие вопросы при разработке таких проектов самые значимые?), была возможность ознакомиться с тем, что можно программировать и без костылей и велосипедов, получая удовольствие от программирования и отладки, программировать эффективнее и быстрее чем на JavaScript, получая в результате более простой, понятный и лучше сопровождаемый код.
lagranzh
03.09.2015 10:52-1А выгружать javascript можно? столкнулся с тем, что чтобы поменять язык у гугл карт, нужно перегружать страницу.
SkanerSoft
03.09.2015 11:06Можете немного подробнее описать суть?
lagranzh
03.09.2015 11:18На сайте показывается карта от google maps. для этого подгружается javascript в заголовке страницы:
maps.googleapis.com/maps/api/js?v=3.exp&libraries=places,drawing&language=ru
И теперь карта будет показываться по русски. Но если пользователь меняет язык, то приходится перегружать страницу, т.к. google api не предусматривает смену языка.
Вот я и подумал, раз можно подгузить javascript, может можно его и выгрузить что бы загрузить заново с другим языком?mwizard
03.09.2015 11:43Универсального способа что-то выгрузить не существует. Например, допустим, что у вас скрипт вот такого вида:
window.googleMaps.language = 'ru';
Как вы предлагаете «отменить» эту операцию, учитывая, что предыдущее состояниеlanguage
, если оно было, уже разрушено?
Что касается именно вашего случая — попробуйте запихнуть карту в iframe. При изменении языка:
1. затените существующую карту и выведите спиннер поверх;
2. создайте второй такой же iframe, но невидимый;
3. повесьте событие на window load в iframe, чтобы загрузилось вообще все — или изнутри iframe отправляйте сообщение родительскому окну через window.postMessage();
4. начните загрузку карты с правильным языком;
5. по завершению загрузки разместите второй iframe в точности на месте первого, и сделайте его видимым и уровнем выше, чем изначальный iframe;
6. удалите предыдущий iframe;
Таким образом, вы получите изменение языка карты без перезагрузки всей страницы. Возможно, есть другие способы изолировать скрипт в браузере, но я не в курсе.
grayfolk
03.09.2015 12:30А что-то такое не подойдет?
lagranzh
03.09.2015 12:56Проблема в том, что язык выбирается в при подгрузке скрипта, и изменить его потом нельзя. Но выше уже подсказали пользовать iframe.
SkanerSoft
03.09.2015 12:59iframe — в вашем случае это действительно хороший выбор. Выглядит натурально и всю страницу перегружать не нужно =)
grayfolk
03.09.2015 13:28+1Так а что мешает выполнить, как по ссылке, еще раз google.load() с другими параметрами?
Подгрузить js с другим языком и выполнить инициализацию карты снова.
lair
Зачем писать собственный велосипед, когда есть AMD, CommonJS и RequireJS, их поддерживающий?
m0sk1t
Мне кажется автор не предложил свой велосипед а просто описал способы.
lair
Когда описываешь способы, неплохо как-то давать им оценку и уточнять применимость.
m0sk1t
Солидарен с вами) Из песочницы всё реже нормальные статьи идут…