Переконайтеся, що зовнішній скрипт завантажений


80

Я створюю плагін jquery і хочу перевірити, чи завантажений зовнішній скрипт. Це для внутрішньої веб-програми, і я можу підтримувати узгодженість імені та розташування сценарію (mysscript.js). Це також плагін ajaxy, який можна викликати багато разів на сторінці.

Якщо я можу перевірити, чи сценарій не завантажений, я завантажу його за допомогою:

jQuery.getScript()

Як я можу перевірити, чи сценарій завантажений, оскільки я не хочу, щоб той самий сценарій завантажувався на сторінку більше одного разу? Це щось, про що мені не слід турбуватися через кешування сценарію?

Оновлення: Можливо, я не маю контролю над тим, хто використовує цей плагін у нашій організації, і, можливо, не зможу домогтися того, щоб сценарій вже не знаходився на сторінці з певним ідентифікатором або без нього, але ім’я сценарію завжди буде в одному місці з те саме ім'я. Я сподіваюся, що зможу використати назву сценарію, щоб перевірити, чи справді він завантажений.


Цей потік знаходиться у верхній частині поширених запитань щодо тегів SO jquery і має величезну різноманітність методів перевірки наявного скрипта stackoverflow.com/questions/1014203/... Багато відгуків про різні методи
charlietfl

Відповіді:


140

Якщо сценарій створює будь-які змінні або функції в глобальному просторі, ви можете перевірити їх існування:

Зовнішня JS (у глобальному масштабі) -

var myCustomFlag = true;

І щоб перевірити, чи це запустилося:

if (typeof window.myCustomFlag == 'undefined') {
    //the flag was not found, so the code has not run
    $.getScript('<external JS>');
}

Оновлення

Ви можете перевірити наявність відповідного <script>тегу, вибравши всі <script>елементи та перевіривши їх srcатрибути:

//get the number of `<script>` elements that have the correct `src` attribute
var len = $('script').filter(function () {
    return ($(this).attr('src') == '<external JS>');
}).length;

//if there are no scripts that match, the load it
if (len === 0) {
    $.getScript('<external JS>');
}

Або ви можете просто запекти цю .filter()функцію прямо в селекторі:

var len = $('script[src="<external JS>"]').length;

Це була гарна відповідь, на жаль, метод jquery.getScript додає скрипт без вказаного джерела. Тож мені не вдалося його знайти. Я використав частину вашої відповіді, щоб це вирішити, тому +1.
AGoodDisplayName

@AGoodDisplayName У функції зворотного виклику для $.getScript()Ви можете встановити глобальний прапор , який може бути перевірений: $.getScript('<external JS>, function () { window.myCustomFlag = true; }'). Тоді ви можете просто перевірити наявність конкретного <script>елемента або myCustomFlagзмінної.
Джаспер

@jasper, так, це, мабуть, найефективніший спосіб це зробити, тому я приймаю вашу відповідь. Щойно закінчив додавати своє рішення (до якого я повинен включити глобальний прапор).
AGoodDisplayName

24
Перевірка сценарію src - це нормально, але проблема полягає в тому, що наявність тегу сценарію з правильним src не означає, що завантажений сам скрипт. Вставка тегу - це лише початок фази завантаження.
Karol

3
@Jasper із запитання Я припустив, що скрипти завантажуються динамічно, вставляючи тег у DOM. Це єдиний випадок, коли один і той же сценарій можна вставляти кілька разів (ніхто не вставляє сценарій у HTML, а потім намагається завантажити його знову динамічно). Отже, як тільки ви вставите тег сценарію, ви все ще чекаєте, поки він завантажиться, і в цьому випадку ваша відповідь не буде працювати, оскільки вона лише перевіряє, чи існує тег сценарію чи ні.
Кароль

19

Відповідь @ jasper є абсолютно правильною, але для сучасних браузерів стандартним рішенням Javascript може бути:

function isScriptLoaded(src)
{
    return document.querySelector('script[src="' + src + '"]') ? true : false;
}

2
За Booleanбажанням ви можете скористатися оператором, а не умовним
CertainPerformance

1
Це може бути простоreturn document.querySelector('script[src="' + src + '"]');
Гаршал Парех

у мене це не спрацювало. наприклад: document.querySelector('head').append(script_el); console.log(isScriptLoaded(script_el.src)повертається, trueале сценарій ще не запущений.
оріадам

13

Занадто багато відповідей на це, але я вважаю, що варто додати це рішення. Він поєднує кілька різних відповідей.

Ключові моменти для мене були

  • додайте тег #id, щоб його було легко знайти, а не дублювати
  • Використовуйте .onload (), щоб дочекатися, поки сценарій завершить завантаження, перш ніж використовувати його

    mounted() {
      // First check if the script already exists on the dom
      // by searching for an id
      let id = 'googleMaps'
      if(document.getElementById(id) === null) {
        let script = document.createElement('script')
        script.setAttribute('src', 'https://maps.googleapis.com/maps/api/js?key=' + apiKey)
        script.setAttribute('id', id)
        document.body.appendChild(script) 
    
        // now wait for it to load...
        script.onload = () => {
            // script has loaded, you can now use it safely
            alert('thank me later')
            // ... do something with the newly loaded script
        }      
      }
    }
    

2
script.onloadправильна відповідь тут. Дякую, що поділились!
Vigs

10

Тепер це було дуже просто, коли я усвідомлюю, як це зробити, завдяки всім відповідям, що привели мене до рішення. Мені довелося відмовитись від $ .getScript (), щоб вказати джерело сценарію ... іноді найкраще робити щось вручну.

Рішення

//great suggestion @Jasper
var len = $('script[src*="Javascript/MyScript.js"]').length; 

if (len === 0) {
        alert('script not loaded');

        loadScript('Javascript/MyScript.js');

        if ($('script[src*="Javascript/MyScript.js"]').length === 0) {
            alert('still not loaded');
        }
        else {
            alert('loaded now');
        }
    }
    else {
        alert('script loaded');
    }


function loadScript(scriptLocationAndName) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = scriptLocationAndName;
    head.appendChild(script);
}

6

Створіть тег сценарію з певним ідентифікатором, а потім перевірте, чи існує цей ідентифікатор?

Крім того, прокрутіть теги скриптів, перевіряючи сценарій 'src' і переконуючись, що вони вже не завантажені з тим самим значенням, що і те, якого ви хочете уникати?

Редагувати: після зворотного зв’язку, що приклад коду буде корисним:

(function(){
    var desiredSource = 'https://sitename.com/js/script.js';
    var scripts       = document.getElementsByTagName('script');
    var alreadyLoaded = false;

    if(scripts.length){
        for(var scriptIndex in scripts) {
            if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
                alreadyLoaded = true;
            }
        }
    }
    if(!alreadyLoaded){
        // Run your code in this block?
    }
})();

Як згадувалось у коментарях ( https://stackoverflow.com/users/1358777/alwin-kesler ), це може бути альтернативою (не порівнянною):

(function(){
    var desiredSource = 'https://sitename.com/js/script.js';
    var scripts = document.getElementsByTagName('script');
    var alreadyLoaded = false;

    for(var scriptIndex in document.scripts) {
        if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
            alreadyLoaded = true;
        }
    }
    if(!alreadyLoaded){
        // Run your code in this block?
    }
})();

Це ідеальне рішення. Я рекомендую другий.
Ілляс Карім,

Було б чудово, якби можна було поставити код з цими ідеями.
Ілляс Карім

document.scripts здається швидшим, ніж document.getElementsByTagName('script')не
тестував

1
@AlwinKesler, погодився. Оновлено код альтернативою. Було б непогано отримати орієнтир.
MyStream

3

Інший спосіб перевірити зовнішній скрипт завантажується чи ні, ви можете використовувати дані функції JQuery і зберігати прапор перевірки. Приклад як:

if(!$("body").data("google-map"))
    {
        console.log("no js");

        $.getScript("https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=initilize",function(){
            $("body").data("google-map",true);

            },function(){
                alert("error while loading script");
            });
        }
    }
    else
    {
        console.log("js already loaded");
    }

3

Об’єднання кількох відповідей зверху у просту у використанні функцію

function GetScriptIfNotLoaded(scriptLocationAndName)
{
  var len = $('script[src*="' + scriptLocationAndName +'"]').length;

  //script already loaded!
  if (len > 0)
      return;

  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = scriptLocationAndName;
  head.appendChild(script);
}

2

Я думаю, що краще використовувати window.addEventListener ('помилка'), щоб виявити помилку завантаження сценарію та спробувати завантажити його знову. Це корисно, коли ми завантажуємо сценарії з сервера CDN. Якщо ми не можемо завантажити скрипт з CDN, ми можемо завантажити його з нашого сервера.

window.addEventListener('error', function(e) {
  if (e.target.nodeName === 'SCRIPT') {
    var scriptTag = document.createElement('script');
    scriptTag.src = e.target.src.replace('https://static.cdn.com/', '/our-server/static/');
    document.head.appendChild(scriptTag);
  }
}, true);

1

Просто перевірте, чи доступна глобальна змінна , якщо не перевірити ще раз . Щоб запобігти перевищенню максимального списку викликів, встановіть час очікування 100 мс :

function check_script_loaded(glob_var) {
    if(typeof(glob_var) !== 'undefined') {
    // do your thing
    } else {
    setTimeout(function() {
    check_script_loaded(glob_var)
    }, 100)
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.