Как загружать и использовать/вызывать динамически JavaScript
Мне нужно динамически загружать файл JavaScript, а затем обращаться к его контенту.
Файл test.js
test = function () {
var pub = {}
pub.defult_id = 1;
return pub;
}()
В этом случае он работает:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/test.js"></script>
</head>
<body>
<script type="text/javascript">
console.log(test.defult_id);
</script>
</body>
</html>
Но мне нужно загрузить его динамически, и таким образом он не работает:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
function loadjs(file) {
var script = document.createElement("script");
script.type = "application/javascript";
script.src = file;
document.body.appendChild(script);
}
loadjs('test.js');
console.log(test.defult_id);
</script>
</body>
</html>
Ошибка: Uncaught ReferenceError: test is not defined(…)
Ответы
Ответ 1
Вы можете сделать это так:
function loadjs(file) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = file;
script.onload = function(){
alert("Script is ready!");
console.log(test.defult_id);
};
document.body.appendChild(script);
}
Для получения дополнительной информации прочитайте эту статью: https://www.nczonline.net/blog/2009/06/23/loading-javascript-without-blocking/
Ответ 2
Есть отличная статья, которую стоит прочитать всем парням, интересующимся загрузкой js-скриптов, в www.html5rocks.com - Погрузитесь в темные воды загрузки скриптов.
В этой статье, рассмотрев множество возможных решений, автор пришел к выводу, что добавление js-скриптов в конец элемента body является наилучшим из возможных способов избежать блокирования рендеринга страницы js-скриптами, тем самым ускоряя время загрузки страницы.
Но автор предлагает другое хорошее альтернативное решение для тех людей, которые отчаянно пытаются загружать и выполнять сценарии асинхронно.
Учитывая, что у вас есть четыре сценария с именем script1.js, script2.js, script3.js, script4.js
, вы можете сделать это с помощью применения async = false:
[
'script1.js',
'script2.js',
'script3.js',
'script4.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
Теперь Спец говорит: скачать вместе, выполнить по порядку, как только все загрузят.
Firefox & lt; 3.6, Opera говорит: Я понятия не имею, что это за асинхронная вещь, но так получилось, что я выполняю сценарии, добавленные через JS, в порядке их добавления.
Safari 5.0 говорит: Я понимаю 'async', но не понимаю, как установить его в 'false' с JS. Я выполню ваши сценарии, как только они приземлятся, в любом порядке.
IE & lt; 10 говорит: Нет понятия об "асинхронности", но есть обходной путь, использующий "onreadystatechange".
Все остальное говорит: Я твой друг, собирался сделать это по книге.
Теперь полный код с IE & lt; 10 обходных путей:
var scripts = [
'script1.js',
'script2.js',
'script3.js',
'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];
// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}
// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else well miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}
Несколько трюков и минимизация позже, его 362 байта
!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
"//other-domain.com/1.js",
"2.js"
])
Ответ 3
Динамическая загрузка JS файлов является асинхронной, поэтому, чтобы обеспечить загрузку script перед вызовом некоторой функции внутри, используйте событие onload в script:
function loadjs(file) {
var script = document.createElement("script");
script.type = "application/javascript";
script.onload=function(){
//at this tine the script is loaded
console.log("Script loaded!");
console.log(test);
}
script.src = file;
document.body.appendChild(script);
}