2010-10-19 1 views
3

Я ищу способ условной загрузки и сохранения порядка выполнения некоторых файлов javascript (внешних и внутренних) без какой-либо зависимости библиотеки. В основном, то, что я хочу сделать, это загрузить их, только если браузер поддерживает localStorage.условно загружать javascript (внешний и внутренний) и сохранять порядок выполнения

Вот в основном моя оболочка:

if (window.localStorage) { 
//load up JS only if it's needed 
    var body = document.getElementsByTagName('body')[0], 
     js1 = document.createElement('script'), 
     js2 = document.createElement('script'), 
     js3 = document.createElement('script'), 
     js4 = document.createElement('script'), 
     js5 = document.createElement('script'); 

    js1.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'; 
    js2.src = 'http://www.google.com/jsapi'; 
    js3.src = 'my_file1.js'; 
    js4.src = 'my_file2.js'; 
    js5.src = 'my_file3.js'; 

    body.appendChild(js1); 
    body.appendChild(js2); 
    body.appendChild(js3); 
    body.appendChild(js4); 
    body.appendChild(js5); 
} else { 
    //no localStorage support, display messaging 
} 

Я пытался динамически добавлять узлы сценария через createElement/body.appendChild но те, похоже, не работает.

Есть ли простой способ достичь этого? Сейчас все работает, но IE6 и IE7 загружают скрипт, который они даже не выполняют, и это то, что я хочу исправить.

+0

@Crowder Глоток, я не знаю, что. Надеюсь, пользователи IE простят меня. :) –

+0

@ Crowder Ну, я убил шутку, я думаю, что было бы хромой пересказывать более умеренную версию. :) –

ответ

5

Добавление script Узлы должны работать нормально. Поскольку эти сценарии будут выполняться асинхронно с добавлением кода, вам нужно будет дать им обратный вызов для вызова следующего порядка. Например:

if (window.localStorage) { 
    // Load the local storage stuff; once loaded, it'll call 
    // `doTheNextThing` 
    var script = document.createElement('script'); 
    script.type = "text/javascript"; 
    script.src = /* ... the URL of the script ... */; 
    document.body.appendChild(script); // Or append it to `head`, doesn't matter 
             // and `document.body` is convenient 
} 
else { 
    // Skip loading it 
    setTimeout(doTheNextThing, 10); 
} 

function doTheNextThing() { 
    // ... 
} 

... где динамический скрипт вы загружаете для localStorage вещи вызова doTheNextThing после загружает   — так и в случае, когда есть localStorage, динамически нагруженный сценарий вызывает doTheNextThing, но в том случае, где нет, код выше. Обратите внимание, что я сделал вызов из вышеприведенного кода асинхронным (через setTimeout): Сделать его всегда асинхронным независимо от того, как он вызван, уменьшает ваши шансы на отсутствие ошибок (например, добавляя то, что полагается на то, что он называется синхронно, а затем забыв проверить это незначительное изменение в IE).

Обновление: Вышеупомянутое предполагает, что вы контролируете скрипт, который вы загружаете, но вы уточнили, что это не так. В таком случае, что вам нужно сделать, это загрузить скрипты, по одному и опрашивать функции, которые они предоставляют (как правило, собственность на window объекта, как window.jQuery), что-то вроде этого (непроверенные):

// Load the script designated by `src`, poll for the appearance 
// of the symbol `name` on the `window` object. When it shows 
// up, call `callback`. Timeout if the timeout is reached. 
function loadAndWait(src, name, timeout, callback) { 
    var stop, script; 

    // Do nothing if the symbol is already defined 
    if (window[name]) { 
     setTimeout(function() { 
      callback("preexisting"); 
     }, 10); 
    } 
    else { 
     // Load the script 
     script = document.createElement('script'); 
     script.type = "text/javascript"; 
     script.src = src; 
     document.body.appendChild(script); 

     // Remember when we should stop 
     stop = new Date().getTime() + timeout; 

     // Start polling, long-ish initial interval 
     setTimeout(poll, 150); 
    } 

    function poll() { 
     if (window[name]) { 
      // Got it 
      callback("loaded"); 
     } 
     else if (new Date().getTime() > stop) { 
      // Time out 
      callback("timeout"); 
     } 
     else { 
      // Keep waiting, shorter interval if desired 
      setTimeout(poll, 75); 
     } 
    } 
} 

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

loadAndWait(
    "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", 
    "jQuery", 
    10000, // ten seconds or whatever 
    function(result) { 
     // ...do the next one if result !== "timeout" 
    } 
); 

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

loadThese(
    [ 
     { src: "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", 
      symbol: "jQuery" 
     }, 
     { 
      src:  "http://the-next-one", 
      symbol: "nextSymbol" 
     } 
    ], 
    doTheNextThing 
); 

function loadThese(scripts, callback) { 
    var index = 0; 
    run("okay"); 

    function run(result) { 
     var entry; 

     if (result === "timeout") { 
      callback(result); 
     } 
     else if (index < scripts.length) { 
      entry = scripts[index++]; 
      loadAndWait(entry.src, entry.symbol, 10000, run); 
     } 
     else { 
      callback("loaded"); 
     } 
    } 
} 

Там, loadThese устанавливает петлю с использованием run для загрузки каждого скрипта по очереди.

Все вышесказанное полностью одета в манжету и, вероятно, может быть затянуто и пуленепробино, но вы получаете идею.

Не в теме, но мой вопрос: действительно ли так много кода, что это проблема для браузеров, которые не могут использовать его для его загрузки? Запрет на файлы, получающие лот больше, вы на самом деле замедляете свой сайт для пользователей с расширенными браузерами, не получая ничего от других. Ниже определенного размера накладные расходы на подключение к серверу для извлечения сценария являются таким же важным фактором, как и его передача. Является ли дополнительный материал 50k кода? Я бы сделал некоторые бенчмаркинга, чтобы проверить, действительно ли это необходимо ... Возможно, это (возможно, у вас уже есть!), Но это стоит только упомянуть ...

Off темы обновления: В обновленном вопросе, вы перечислить пять отдельных сценариев вы бы загрузку, если localStorage поддерживаются. Даже если предположить, что вы получаете все пять из разных CDN, это много индивидуальных запросов на скрипт (независимо от того, выполняются ли они обычным способом или как указано выше), каждый из которых имеет для обработки по одному. Это проблема производительности загрузки страницы, ожидающая появления. Несмотря на (возможно) потерю преимуществ CDN и существующего кэширования, вы можете посмотреть на захват всех этих сценариев, их объединение и размещение вашей комбинированной версии в одном файле. См. «Минимизировать запросы HTTP» в YUI performance "rules" (я предпочитаю термин «руководство», но что бы ни было). Это также упростит вашу динамическую загрузку.

+0

Я не понимаю обратного вызова. Как вы загрузите следующие 2 внешних файла http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js и http://www.google.com/jsapi, а также внутренний JS-файл, скажем my_file1.js? – magenta

+0

if (window.localStorage) { var body = document.getElementsByTagName ('body') [0]; \t СП1 = document.createElement ('Скрипт'), \t СП2 = document.createElement ('Скрипт'), \t СП3 = document.createElement ('Скрипт'); \t \t js1.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'; \t js2.src = 'http://www.google.com/jsapi'; \t js3.src = 'my_file1.js'; \t body.appendChild (js1); \t body.appendChild (js2); \t body.appendChild (js3); } Это не работает для меня. – magenta

+0

@magenta: Извините, я предположил, что вы контролируете другие скрипты и можете поместить вызов doTheNextThing(); 'в них (теперь я понимаю« внешнюю и внутреннюю »часть заголовка!). Одна секунда, есть другой способ. –

0

Я пришел, чтобы использовать этот код. Обе основные функции (addEvent и load_javascript) находятся в Интернете.
Я не пытался уменьшить размер загрузки: это единственный способ загрузить ресурсы. Итак, возможно, идея, предложенная , Šime Vidas имеет смысл для вас.

addEvent = function(elm, evType, fn, useCapture) { 
    //Credit: Function written by Scott Andrews 
    //(slightly modified) 
    var ret = 0; 

    if (elm.addEventListener) { 
     ret = elm.addEventListener(evType, fn, useCapture); 
    } else if (elm.attachEvent) { 
     ret = elm.attachEvent('on' + evType, fn); 
    } else { 
     elm['on' + evType] = fn; 
    } 

    return ret; 
}; 


    var left_to_load = 0; 
    function init() { 
     --left_to_load; 
     if (left_to_load > 0) { 
      return; 
     } 

     // all scripts are loaded now 
     // proceed with your logic 
    } 

    // load js file and call function when done 
    function load_javascript(src, callback) { 
     var a = document.createElement('script'); 
     a.type = 'text/javascript'; 
     a.src = src; 
     var s = document.getElementsByTagName('script')[0]; 
     s.parentNode.insertBefore(a, s); 

     ++left_to_load; 
     addEvent(a, 'load', callback, false); 
    } 



load_javascript('url1', init); 
load_javascript('url2', init); 
... 
2

Вы можете использовать комбинацию функций включения и выключения. Что-то вроде следующего:

function loadScripts(index) { 
    return function() { 
     var e = document.createElement('script'); 
     e.src = scripts[index]; 
     document.body.appendChild(e); 

     if (index + 1 < scripts.length) { 
      e.onload = loadScripts(index + 1) 
     } 
    }; 
} 

И ссылаться на это следующим образом:

loadScripts(0)();