Verifique que el script externo esté cargado

80

Estoy creando un complemento jquery y quiero verificar que se cargue un script externo. Esto es para una aplicación web interna y puedo mantener el nombre / ubicación del script consistente (mysscript.js). Este también es un complemento ajaxy al que se puede llamar muchas veces en la página.

Si puedo verificar que el script no está cargado, lo cargaré usando:

jQuery.getScript()

¿Cómo puedo verificar que el script esté cargado porque no quiero que el mismo script se cargue en la página más de una vez? ¿Es esto algo de lo que no debería preocuparme debido al almacenamiento en caché del script?

Actualización: es posible que no tenga control sobre quién usa este complemento en nuestra organización y es posible que no pueda hacer cumplir que el script no esté ya en la página con o sin una ID específica, pero el nombre del script siempre estará en el mismo lugar con el mismo nombre. Espero poder usar el nombre del script para verificar que esté realmente cargado.

AGoodDisplayName
fuente
Este hilo se encuentra en la parte superior de las preguntas frecuentes sobre etiquetas SO jquery y tiene una gran variedad de métodos para verificar el script existente stackoverflow.com/questions/1014203/… Muchos comentarios sobre varios métodos
charlietfl

Respuestas:

140

Si el script crea variables o funciones en el espacio global, puede verificar su existencia:

JS externo (en alcance global) -

var myCustomFlag = true;

Y para verificar si esto se ha ejecutado:

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

Actualizar

Puede verificar la existencia de la <script>etiqueta en cuestión seleccionando todos los <script>elementos y verificando sus srcatributos:

//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>');
}

O simplemente puede hornear esta .filter()funcionalidad directamente en el selector:

var len = $('script[src="<external JS>"]').length;
Jaspe
fuente
Esta fue una buena respuesta, desafortunadamente el método jquery.getScript agrega el script sin una fuente especificada. Entonces no pude encontrarlo. Usé parte de tu respuesta para resolver esto, así que +1.
AGoodDisplayName
@AGoodDisplayName En la devolución de llamada para $.getScript()que pueda establecer un indicador global que puede ser verificado: $.getScript('<external JS>, function () { window.myCustomFlag = true; }'). Luego, puede verificar la existencia del <script>elemento específico o la myCustomFlagvariable.
Jasper
@jasper, sí, esa es probablemente la forma más eficiente de hacerlo, por eso estoy aceptando tu respuesta. Acabo de terminar de poner mi solución (en la que debería incluir una bandera global).
AGoodDisplayName
24
La verificación del script src está bien, pero el problema es que la existencia de una etiqueta de script con el src correcto no implica que el mismo script esté cargado. Insertar etiqueta es solo el comienzo de la fase de carga.
Karol
3
@Jasper de una pregunta asumí que los scripts se cargan dinámicamente, insertando la etiqueta en DOM. Este es el único caso en el que puede tener el mismo script insertado varias veces (nadie inserta el script en HTML y luego intenta cargarlo de nuevo dinámicamente). Entonces, una vez que inserta la etiqueta de secuencia de comandos, todavía espera hasta que se cargue, y en este caso su respuesta no funcionará, porque solo verifica si la etiqueta de secuencia de comandos existe o no.
Karol
19

La respuesta de @ jasper es totalmente correcta, pero con los navegadores modernos, una solución estándar de Javascript podría ser:

function isScriptLoaded(src)
{
    return document.querySelector('script[src="' + src + '"]') ? true : false;
}
Abhishek
fuente
2
Puede usar en Booleanlugar del operador condicional, si lo desea
CertainPerformance
1
Simplemente puede serreturn document.querySelector('script[src="' + src + '"]');
Harshal Parekh
esto no funcionó para mí. por ejemplo: document.querySelector('head').append(script_el); console.log(isScriptLoaded(script_el.src)devuelve truepero el script aún no se ejecutó.
Oriadam
13

Pocas respuestas en este caso, pero creo que vale la pena agregar esta solución. Combina algunas respuestas diferentes.

Los puntos clave para mí fueron

  • agregue una etiqueta #id, para que sea fácil de encontrar y no duplicar
  • Use .onload () para esperar hasta que el script haya terminado de cargarse antes de usarlo

    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
        }      
      }
    }
    
comfytoday
fuente
2
script.onloades la respuesta correcta aquí. ¡Gracias por compartir!
Vigs
10

Esto fue muy simple ahora que me doy cuenta de cómo hacerlo, gracias a todas las respuestas por llevarme a la solución. Tuve que abandonar $ .getScript () para especificar la fuente del script ... a veces es mejor hacer las cosas manualmente.

Solución

//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);
}
AGoodDisplayName
fuente
6

¿Cree la etiqueta de secuencia de comandos con una identificación específica y luego verifique si esa identificación existe?

Alternativamente, recorra las etiquetas de script para verificar el script 'src' y asegúrese de que no estén cargadas con el mismo valor que el que desea evitar

Editar: siguiendo los comentarios de que un ejemplo de código sería útil:

(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?
    }
})();

Como se menciona en los comentarios ( https://stackoverflow.com/users/1358777/alwin-kesler ), esta puede ser una alternativa (no comparada):

(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?
    }
})();
Mi corriente
fuente
Esta es la solución perfecta. Recomiendo el segundo.
Ilyas karim
Sería genial si pudiera poner código con estas ideas.
Ilyas karim
document.scripts parece más rápido que document.getElementsByTagName('script')pero no lo he probado
Alwin Kesler
1
@AlwinKesler, estuvo de acuerdo. Se actualizó el código con una alternativa. Sería bueno obtener un punto de referencia.
MyStream
3

Otra forma de verificar que un script externo esté cargado o no, puede usar la función de datos de jquery y almacenar una bandera de validación. Ejemplo como:

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");
    }
Sunil Sharma
fuente
3

Fusionar varias respuestas de arriba en una función fácil de usar

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);
}
Aaron Sherman
fuente
2

Creo que es mejor usar window.addEventListener ('error') para capturar el error de carga del script e intentar cargarlo nuevamente. Es útil cuando cargamos scripts desde un servidor CDN. Si no podemos cargar el script desde la CDN, podemos cargarlo desde nuestro servidor.

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);
Duque
fuente
1

Simplemente verifique si la variable global está disponible , si no , vuelva a verificar . Para evitar que se exceda la pila de llamadas máxima, establezca un tiempo de espera de 100 ms en la verificación:

function check_script_loaded(glob_var) {
    if(typeof(glob_var) !== 'undefined') {
    // do your thing
    } else {
    setTimeout(function() {
    check_script_loaded(glob_var)
    }, 100)
    }
}
Cibernético
fuente