условно загрузить javascript (внешний и внутренний) и сохранить порядок исполнения - PullRequest
3 голосов
/ 20 октября 2010

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

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

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 загружают сценарий, который они даже не выполняют, и это то, что я хочу исправить.

Ответы [ 3 ]

5 голосов
/ 20 октября 2010

Добавление 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 для загрузки каждого скрипта по очереди.

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

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

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

2 голосов
/ 30 апреля 2011

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

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)();
0 голосов
/ 20 октября 2010

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

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);
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...