Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Динамическое подключение скриптов (https://javascript.ru/forum/events/6050-dinamicheskoe-podklyuchenie-skriptov.html)

Dimanoid 08.11.2009 18:07

Динамическое подключение скриптов
 
Сразу прошу прощения, если написал не в тот раздел.

Проблема такая:
К HTML-странице подключается внешний скрипт. В процессе работы он подключает к странице еще один скрипт и добавляет его в конец/начало (пробовал оба варианта) тэга HEAD. После этого мне надо чтобы первый скрипт вызывал функцию из нового. Но,насколько я понял логику, новый скрипт прочитается только после выполнения текущего. Нельзя ли заставить браузер прочитать новый скрипт сразу после подключения? Хочется видеть новый скрипт именно в отдельном js-файле.

Вот мой код:
HTML-файл:
Код:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">

<head>
        <title>Привет!</title>
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
        <script type="text/javascript" src="/sys/kernel"></script>
</head>

<body>
</body>
</html>

Вот скрипт kernel:
function addScript(src)
{
     var newScript = document.createElement("script");
     newScript.type = "text/javascript";
     newScript.src =  src;
     var first = document.getElementsByTagName("head")[0].firstChild;
     document.getElementsByTagName("head")[0].insertBefore(newScript, first);
// Сначала пробовал document.getElementsByTagName("head")[0].appendChild(newScript);
}
addScript("/sys/modules/hello/main.js");
main(); //Это вызов функции из main.js

Скрипт main.js:
function main()
{
alert("Работает");
}


Можно конечно в конце файла main.js дописать main(); но не хочется так делать, потому что мне надо, чтобы main.js выполнился не сразу после подключения, а через несколько строк кода (код kernel я очень обрезал, он большой).

Заранее спасибо за помощь!

Snowcore 10.11.2009 14:38

можно создать функцию, которая периодически будет проверять загружен ли main.js:
для этого используйте setInterval, а в функции делайте проверку, например:

if (typeof(main) != undefined) {
  ...
}

Dimanoid 10.11.2009 22:20

Snowcore,
Это не совсем то, т.к. все равно функция main() вызовется после прочтения всего kernel, а хотелось бы, чтобы она вызывалась до окончания кода kernel.

is5201 20.01.2010 08:14

Предлагаю вот что:
Код:

<body>
        <script>
function addScript(url) {
			var xmlhttp;
			
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				};
			};
			
			if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
				xmlhttp = new XMLHttpRequest();
			};
			
			xmlhttp.open('GET', url, false);
			xmlhttp.send(null);
		
			var obj = document.createElement('script');
			var textScr = document.createTextNode(xmlhttp.responseText);
			
			document.body.appendChild(obj);
			obj.appendChild(textScr);
		};
		
		addScript('script.js');
		some_func();

        </script>
       
        <button onclick="some_func()">Click ME!!!</button>
</body>

Содержимое script.js:
Код:

function some_func() {alert(1)};

Сразу говорю: в мелкомягком не работает.
Кто придумает как победить ослика пишите).

Ex_Soft 20.01.2010 08:34

тынць?

is5201 20.01.2010 09:03

Теперь кушает и IE:
Код:

<body>
<script>
		function addScript(url) {
			var xmlhttp;
			
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				};
			};
			
			if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
				xmlhttp = new XMLHttpRequest();
			};
			
			xmlhttp.open('GET', url, false);
			xmlhttp.send(null);
			
			if (navigator.appName=="Microsoft Internet Explorer") {
				var ifr = document.createElement('iframe');
				document.body.appendChild(ifr);
				ifr.document.write("<script>"+xmlhttp.responseText+"<\/script>");
				document.body.removeChild(ifr);
			} else {
				var obj = document.createElement('script');
				var textScr = document.createTextNode(xmlhttp.responseText);
				document.body.appendChild(obj);
				obj.appendChild(textScr);
			};
		};
		
		addScript('script.js');
		some_func();

        </script>
       
        <button onclick="some_func()">Click ME!!!</button>
</body>


Kolyaj 20.01.2010 09:40

Цитата:

Сообщение от is5201
Предлагаю вот что:

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

И вы что, в IE скрипт в iframe выполняете? :blink:

В IE есть функция execScript.

Ex_Soft 20.01.2010 11:55

Зачем мутить с XMLHttpRequest в синхронном режиме для того, чтобы дождаться окончания загрузки файла, если у <script> ЭстЪ onload? Дрозофила:
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
		<title>Test load JS</title>
		<script type="text/javascript">
<!--
function LoadBySrc(dest)
{
	var
		CtrlLog=document.getElementById("Log");

	CtrlLog.value+="LoadBySrc(\""+dest+"\")\r\n";

	CtrlLog.value+=(("F1inJS1" in this) ? "" : "!")+"\"F1inJS1\" in this\r\n";
	CtrlLog.value+=(("F1inJS1" in window) ? "" : "!")+"\"F1inJS1\" in window\r\n";

	if(("F1inJS1" in this)
		|| ("F1inJS1" in window))
		return;

	var
		h,
		s;

	if((h=document.getElementsByTagName(dest))
		&& h.length>0)
	{
		h=h[0];
		if(s=document.createElement("script"))
		{
			s.id="js1";
			s.type="text/javascript";
			s.charset="windows-1251";

			if("attachEvent" in s)
				s.attachEvent("onload",OnLoad);
			else if("addEventListener" in s)
				s.addEventListener("load",OnLoad,false);
			else
				s.onload=OnLoad;
			if("onreadystatechange" in s)
				s.onreadystatechange=function(){if(this.readyState=="complete") OnLoad()};

			s.src="js1.js";
			h.appendChild(s);

			CtrlLog.value+=(("F1inJS1" in this) ? "" : "!")+"\"F1inJS1\" in this\r\n";
			CtrlLog.value+=(("F1inJS1" in window) ? "" : "!")+"\"F1inJS1\" in window\r\n";
		}
	}
}

function OnLoad()
{
	var
		CtrlLog=document.getElementById("Log");

	CtrlLog.value+="script OnLoad ("+(("F1inJS1" in this) ? "" : "!")+"\"F1inJS1\" in this)\r\n";
	CtrlLog.value+="script OnLoad ("+(("F1inJS1" in window) ? "" : "!")+"\"F1inJS1\" in window)\r\n";

	F1inJS1();
}
// -->
		</script>
	</head>
	<body>
		<input type="button" id="btnLoadBySrcHead" value="Load by src (head)" onclick="LoadBySrc('head')">
		<textarea id="Log" name="Log" rows="12" cols="80" readonly></textarea>
	</body>
</html>

function F1inJS1()
{
	alert("F1 in JS1");
}

Mozilla Firefox 3.5.7, M$ IE 6.0.2900.2180.xpsp_sp2_rtm040803-2158 - все сухо...

Dimanoid 20.01.2010 13:40

Ой, моя тема продолжается :) Спасибо за решение, но необходимость уже отпала, я просто обошелся без такого подключения.
Спасибо всем за помощь!

ЗЫ Совместимость с ИЕ, кстати, меня не очень волнует. Пора переходить на нормальные браузеры.

is5201 20.01.2010 13:55

Если вы хотите разделять функцию на две никаких проблем нет. Но если мы хотим сделать все в одной: подгрузить библиотеку и выполнить один из её методов, может возникнуть проблема. Метод может просто не успеть подгрузиться. Поэтому я и делаю синхронный запрос - подгружаю данные, а затем пытаюсь сделать доступными функции библиотеки.
С iframe конечно моя промашка). Вот рабочий код:
Код:

<body>
        <script>
function addScript(url) {
			var xmlhttp;
			
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				};
			};
			
			if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
				xmlhttp = new XMLHttpRequest();
			};
			
			xmlhttp.open('GET', url, false);
			xmlhttp.send(null);
			
			if (navigator.appName=="Microsoft Internet Explorer") {
				window.execScript(xmlhttp.responseText);
			} else {
				var obj = document.createElement('script');
				var textScr = document.createTextNode(xmlhttp.responseText);
				document.body.appendChild(obj);
				obj.appendChild(textScr);
			};
		};
		
		addScript('script.js');
		some_func();

        </script>
</body>

Содержимое script.js:
Код:

function some_func() {
	alert('some func');
};
function some_func2() {
	alert('some func2');
};

Совместимость: IE5+, Opera9+, Firefox.


Часовой пояс GMT +3, время: 04:18.