Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Подскажите как быть в данной ситуации (https://javascript.ru/forum/misc/34525-podskazhite-kak-byt-v-dannojj-situacii.html)

Saffoniy 08.01.2013 21:45

Подскажите как быть в данной ситуации
 
Ситуация следующая, у меня сайт работает на основе ajax, history api
http://history.spb-piksel.ru/ вот этого движка, страницы грузятся у меня асинхронно, после чего js скрипты которые находились на странице отказываются работать, как быть?
-------------------------------
И еще, я использую на сайте асинхронную загрузку js скриптов
$Load = function (c, d) {
    for (var b = c.length, e = b, f = function () {
            if (!(this.readyState
                && this.readyState !== "complete"
                && this.readyState !== "loaded")) {
                this.onload = this.onreadystatechange = null;
                --e || d()
            }
        }, g = document.getElementsByTagName("head")[0], i = function (h) {
            var a = document.createElement("script");
            a.async = true;
            a.src = h;
            a.onload = a.onreadystatechange = f;
            g.appendChild(a)
        }; b;) i(c[--b])
};

Так это работает
$Load(['/js/script.js'], function () {alert('script loaded');});

При использовании такого способа асинхронной загрузки js скриптов, скрипты на странице дублируются при каждом переходе на страницу, то есть скрипты которые указаны в $Load(['']); один раз нормально загружаются, а потом просто повторно снова грузятся и все когда по страницам ходишь - извиняюсь если не внятно объяснил, как можно исключить дублирование скриптов? Или как решить проблемы с тем что при переходе по страницам скрипты как встроенные, так и внешние которые были на странице отказываются работать?

DjDiablo 08.01.2013 23:24

Ну дак вроде очевидно.
Запоминайте имена скриптов в массиве, которые уже загружены или ещё находятся в процессе загрузки, и если добавленный в загрузку скрипт уже присутствует в массиве, то не грузите его.

После того как страница по ajax загружена, кидайте глобально событие pageload, пусть ваши скрипты слушают это события, и выполняют необходимый функционал. К примеру обычный скрипт слайд шоу в ответ на событие pageload, может подцепить это слайд шоу ко всем вновь найденным DOM элементам с классом .slideshow

devote 09.01.2013 18:24

Кину сюда то что писал человеку на почту:

$Load = (function() {

    // в этой переменной будем хранить ссылки на скрипты которые уже загружали
    var loadedScripts = {};

    function loadAsync(src, callback) {

        if (src in loadedScripts) {
            callback(loadedScripts[src] || src);
        } else {
            var script = document.createElement('script');
            script.type = 'text/javascript';

            if ("onload" in script || !("readyState" in script)) {
                script.onload = function() {
                    callback(src);
                }
            } else {
                script.onreadystatechange = function() {
                    if (this.readyState == "loaded" ||
                            this.readyState == "complete") {
                        callback(src);
                    }
                }
            }

            script.src = src;
            document.documentElement.firstChild.appendChild(script);
        }
    }

    function loader(scripts, onload) {

        scripts = typeof scripts === "string" ? [scripts] : scripts;

        var
            asyncCallback,
            length = loader.instances.length;

        if (scripts.length === 0) {
            return onload && onload.call(this);
        }

        loadAsync(scripts.shift(), asyncCallback = function(src) {
            if (typeof src === "function") {
                src();
            } else if (loader.instances.length > length) {
                loadedScripts[src] = loader.instances[ length++ ];
                loadedScripts[src]();
            } else {
                loadedScripts[src] = null;
            }

            if (scripts.length === 0) {
                onload && onload.call(this);
            } else {
                loadAsync(scripts.shift(), asyncCallback);
            }
        });
    }

    loader.instances = [];

    return loader;
})();


Использовать примерно так:
$Load(['script1.js', 'script2.js'], function() {
    // loaded
});

// ну или вместо массива строка:
$Load('script1.js', function() {
    // loaded
});


Далее в каждом скрипте который загружаете аяксом, код который нужно снова выполнить, обернуть вот так:
$Load.instances.push(function(){
    // тут ваш код, который будет автоматически выполнен
    // после загрузки или в уже загруженном скрипте.
});

DjDiablo 09.01.2013 21:56

devote помоему чересчур замороченно
попробывал покороче и попроще сделать.
проверено хром, опера, ie.

код
$Load = (function() {
    var loadedScripts = {},//только загруженные скрипты
        allscript={};//все скрипты

    //хелпер для установки обработчиков событий
    function event(el,event,fn) {
         if (el.readyState=="complete") return fn(); 	
         var count= (event=="readystatechange") ? 2:1;
         if ( el.addEventListener) el.addEventListener (event, fn ,false)
         else el.attachEvent("on"+event, function(){ count--; if (count==0) fn() } );
    }  

    //грузит скрипт и вешает событие load
    function loadAsync(src, callback) {
         setTimeout(function(){
	        if (! (src in allscript) ) {
                    var script = document.createElement('script');
                    script.type = 'text/javascript';
                    script.src = src;
                    document.documentElement.firstChild.appendChild(script);	       
                    allscript[src]=script;
	         }
             event( allscript[src], '\v'!='v'?'load':"readystatechange",function(){ 					
                   callback(src,script) 
             }) 				
         },1)			
    }

    //возвращаем функцию
    return function (scripts, onload) {
	        var scripts = typeof scripts === "string" ? [scripts] : scripts,
	            count=scripts.length;

	        for( var i = 0; i < scripts.length; i++ ) {
	              if (scripts[i] in loadedScripts ) count--; 
	              else loadAsync( scripts[i], function(src,script){			
	                loadedScripts[src]=script;
	                count--;
	                if ( count==0) onload();		
	              });
	        }               	
	        if (count==0) onload();
    }
})();


использование
$Load(["test.js","test2.js","test.js","test.js"],function(){ 
   alert("result");
});

devote 10.01.2013 00:02

Цитата:

Сообщение от DjDiablo
devote помоему чересчур замороченно

ну я не старался, написал за 10 минут, главное работает. А оптимизация дело второе... Плюс ты не учел запуск скриптов, что уже загружены. Я специально ввел для этого instances

devote 10.01.2013 00:16

ну и плюс ко всему такой код читать тяжело:
...
    function event(el,event,fn) {
         if (el.readyState=="complete") return fn();    
         var count= (event=="readystatechange") ? 2:1;
         if ( el.addEventListener) el.addEventListener (event, fn ,false)
         else el.attachEvent("on"+event, function(){ count--; if (count==0) fn() } );
    }
...

А если его привести в читаемый вид, то не многим меньше он станет:
$Load = (function() {
    var loadedScripts = {},//только загруженные скрипты
        allscript={};//все скрипты
 
    //хелпер для установки обработчиков событий
    function event(el, event, fn) {
        if (el.readyState == "complete") {
            return fn();
        }

        var count = (event == "readystatechange") ? 2 : 1;

        if (el.addEventListener) {
            el.addEventListener(event, fn ,false);
        } else {
            el.attachEvent("on" + event, function(){
                count--;
                if (count == 0) {
                    fn();
                }
            });
        }
    }

    //грузит скрипт и вешает событие load
    function loadAsync(src, callback) {
        setTimeout(function() {
            if (!(src in allscript)) {
                var script = document.createElement('script');
                script.type = 'text/javascript';
                script.src = src;
                document.documentElement.firstChild.appendChild(script);           
                allscript[src] = script;
            }
            event(allscript[src], '\v' != 'v' ? 'load' : "readystatechange", function() {
                callback(src, script);
            });
        }, 1);
    }
 
    //возвращаем функцию
    return function (scripts, onload) {
        var scripts = typeof scripts === "string" ? [scripts] : scripts,
            count = scripts.length;
 
        for(var i = 0; i < scripts.length; i++) {
            if (scripts[i] in loadedScripts) {
                count--;
            } else {
                loadAsync(scripts[i], function(src, script){         
                    loadedScripts[src] = script;
                    count--;
                    if (count == 0) {
                        onload();
                    }
                });
            }
        }

        if (count == 0) {
            onload();
        }
    }
})();

Плюс таймеры это излишек,

плюс проверка: (event == "readystatechange") ? 2 : 1;
совсем не правильно, ибо гарантии нет что отработает именно два раза

плюс условие '\v' != 'v'
это вообще из разряда идиотизма, ибо код написанный с использованием багов браузера, может привести к неожиданным последствиям. Такое нужно использовать только в крайней необходимости. Ибо при эмуляции того же ИЕ8 в ИЕ9 не факт что проявится это баг, хотя я и не проверял.

DjDiablo 10.01.2013 00:33

спасибо что глянул.
Там был ряд костылей, но я их уже выпилил :)
чем посоветуешь заменить '\v'!='v' может if (el.attachEvent) попробывать.
посмотри кстатии самый короткий способ определить ie

последняя версия,
всё ковырять больше небуду,надоело :)

$Load = (function() {
    var loadedScripts = {},//только загруженные скрипты
        allscript={};//все скрипты

    //хелпер для установки обработчиков событий
    function event(el,fn) {
       if ( '\v'!='v') el.addEventListener ("load", fn ,false)
       else el.attachEvent("onreadystatechange", function(){
                 if (el.readyState=="complete" || el.readyState=="loaded") fn()
       });
    }  

    //грузит скрипт и вешает событие load
    function loadAsync(src, callback) {
          if (! (src in allscript) ) {
              var script = document.createElement('script');
              script.type = 'text/javascript';
              script.src = src;
              document.documentElement.firstChild.appendChild(script);	       
              allscript[src]=script;
          }

          event( allscript[src], function(){
	         loadedScripts[src]=allscript[src]; 					
             callback(src) 
         }) 				
    }

    //возвращаем функцию
    return function (scripts, onload) {
	        var scripts = typeof scripts === "string" ? [scripts] : scripts,
	            count=scripts.length;

	        for( var i = 0; i < scripts.length; i++ ) {
	              if (scripts[i] in loadedScripts ) count--; 
	              else loadAsync( scripts[i], function(src){			
	                count--;
	                if ( count==0) onload();		
	              });
	        }               	
	        if (count==0) onload();
    }
})();

devote 10.01.2013 00:34

ну вот уменьшил свой код, столько же строк стало что и у тебя, безо всяких таймеров, хаков с багами и прочей неприятной ерунды)))

devote 10.01.2013 00:35

Цитата:

Сообщение от DjDiablo
последняя версия,
всё ковырять больше небуду,надоело

как скажешь, но ты все же забыл про instances :)

DjDiablo 10.01.2013 01:37

ты свой скрипт переписал.
Жулик :D


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