it-swarm.com.de

jQuery.getScript-Alternative in nativem JavaScript

Ich versuche, JS-Skripte dynamisch zu laden, aber die Verwendung von jQuery ist keine Option.

Ich habe die jQuery-Quelle überprüft, um zu sehen, wie getScript implementiert wurde, damit ich diesen Ansatz zum Laden von Skripten mit nativem JS verwenden kann. GetScript ruft jedoch nur jQuery.get () auf

und ich war nicht in der Lage zu finden, wo die Get-Methode implementiert ist.

Also meine Frage ist,

Wie kann ich meine eigene getScript-Methode mit nativem JavaScript zuverlässig implementieren?

Vielen Dank!

43
ILikeTacos

Sie können Skripte wie folgt abrufen:

(function(document, tag) {
    var scriptTag = document.createElement(tag), // create a script tag
        firstScriptTag = document.getElementsByTagName(tag)[0]; // find the first script tag in the document
    scriptTag.src = 'your-script.js'; // set the source of the script to your script
    firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag); // append the script to the DOM
}(document, 'script'));
29
Mathletics

Hier ist eine jQuery getScript-Alternative mit Callback-Funktionalität:

function getScript(source, callback) {
    var script = document.createElement('script');
    var prior = document.getElementsByTagName('script')[0];
    script.async = 1;

    script.onload = script.onreadystatechange = function( _, isAbort ) {
        if(isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
            script.onload = script.onreadystatechange = null;
            script = undefined;

            if(!isAbort && callback) setTimeout(callback, 0);
        }
    };

    script.src = source;
    prior.parentNode.insertBefore(script, prior);
}
82
Mahn

Erstens, Danke für die Antwort von @ Mahn. Ich habe seine Lösung in ES6 umgeschrieben und verspreche, falls jemand sie braucht, werde ich meinen Code einfach hier einfügen:

const loadScript = (source, beforeEl, async = true, defer = true) => {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script');
    const prior = beforeEl || document.getElementsByTagName('script')[0];

    script.async = async;
    script.defer = defer;

    function onloadHander(_, isAbort) {
      if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
        script.onload = null;
        script.onreadystatechange = null;
        script = undefined;

        if (isAbort) { reject(); } else { resolve(); }
      }
    }

    script.onload = onloadHander;
    script.onreadystatechange = onloadHander;

    script.src = source;
    prior.parentNode.insertBefore(script, prior);
  });
}

Verwendung:

const scriptUrl = 'https://www.google.com/recaptcha/api.js?onload=onRecaptchaLoad&render=explicit';
loadScript(scriptUrl).then(() => {
  console.log('script loaded');
}, () => {
  console.log('fail to load script');
});

und Code ist eslinted.

11
AXE

benutze das

var js_script = document.createElement('script');
js_script.type = "text/javascript";
js_script.src = "http://www.example.com/script.js";
js_script.async = true;
document.getElementsByTagName('head')[0].appendChild(js_script);
8
Rohit Agrawal

Mozilla Developer Network bietet ein Beispiel das asynchron arbeitet und nicht 'onreadystatechange' (aus @ ShaneXs Antwort) verwendet, das in einem HTMLScriptTag nicht wirklich vorhanden ist:

function loadError(oError) {
  throw new URIError("The script " + oError.target.src + " didn't load correctly.");
}

function prefixScript(url, onloadFunction) {
  var newScript = document.createElement("script");
  newScript.onerror = loadError;
  if (onloadFunction) { newScript.onload = onloadFunction; }
  document.currentScript.parentNode.insertBefore(newScript, document.currentScript);
  newScript.src = url;
}

Beispielnutzung:

prefixScript("myScript1.js");
prefixScript("myScript2.js", function () { alert("The script \"myScript2.js\" has been correctly loaded."); });

@Agamemnus 'Kommentar sollte jedoch beachtet werden: Das Skript wird möglicherweise nicht vollständig geladen, wenn onloadFunction aufgerufen wird. Ein Timer könnte setTimeout(func, 0) verwenden, damit die Ereignisschleife das dem Dokument hinzugefügte Skript abschließt. Die Ereignisschleife ruft schließlich die Funktion hinter dem Timer auf, und das Skript sollte zu diesem Zeitpunkt einsatzbereit sein.

Vielleicht sollte man jedoch in Betracht ziehen, ein Versprechen zurückzugeben, anstatt zwei Funktionen für die Behandlung von Ausnahmen und Erfolgen bereitzustellen. Dies wäre die ES6-Methode. Dies würde auch die Notwendigkeit eines Timers unnötig machen, da Versprechungen von der Ereignisschleife verarbeitet werden - da das Skript zum Zeitpunkt der Verarbeitung der Versprechung bereits von der Ereignisschleife abgeschlossen wurde.

Nach der Implementierung der Mozilla-Methode einschließlich Promises sieht der endgültige Code folgendermaßen aus:

function loadScript(url)
{
  return new Promise(function(resolve, reject)
  {
    let newScript = document.createElement("script");
    newScript.onerror = reject;
    newScript.onload = resolve;
    document.currentScript.parentNode.insertBefore(newScript, document.currentScript);
    newScript.src = url;
  });
}

loadScript("test.js").then(() => { FunctionFromExportedScript(); }).catch(() => { console.log("rejected!"); });
1
m.w.

Hier gibt es einige gute Lösungen, aber viele sind veraltet. Es gibt ein gutes von @Mahn, aber wie in einem Kommentar angegeben, ist es kein Ersatz für $.getScript(), da der Rückruf keine Daten empfängt. Ich hatte bereits meine eigene Funktion als Ersatz für $.get() geschrieben und bin hier gelandet, wenn ich sie für ein Skript benötige. Ich konnte die @ Mahn-Lösung verwenden und sie zusammen mit meiner aktuellen $.get() -Ersetzung ein wenig modifizieren und mir etwas einfallen lassen, das gut funktioniert und einfach zu implementieren ist.

function pullScript(url, callback){
    pull(url, function loadReturn(data, status, xhr){
        //If call returned with a good status
        if(status == 200){
            var script = document.createElement('script');
            //Instead of setting .src set .innerHTML
            script.innerHTML = data;
            document.querySelector('head').appendChild(script);
        }
        if(typeof callback != 'undefined'){
            //If callback was given skip an execution frame and run callback passing relevant arguments
            setTimeout(function runCallback(){callback(data, status, xhr)}, 0);
        }
    });
}

function pull(url, callback, method = 'GET', async = true) {
    //Make sure we have a good method to run
    method = method.toUpperCase();
    if(!(method === 'GET'   ||   method === 'POST'   ||  method === 'HEAD')){
        throw new Error('method must either be GET, POST, or HEAD');
    }
    //Setup our request
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == XMLHttpRequest.DONE) {   // XMLHttpRequest.DONE == 4
            //Once the request has completed fire the callback with relevant arguments
            //you should handle in your callback if it was successful or not
            callback(xhr.responseText, xhr.status, xhr);
        }
    };
    //Open and send request
    xhr.open(method, url, async);
    xhr.send();
}

Jetzt haben wir einen Ersatz für $.get() und $.getScript(), die genauso einfach funktionieren:

pullScript(file1, function(data, status, xhr){
    console.log(data);
    console.log(status);
    console.log(xhr);
});

pullScript(file2);

pull(file3, function loadReturn(data, status){
    if(status == 200){
        document.querySelector('#content').innerHTML = data;
    }
}
0
Xandor