web-dev-qa-db-fra.com

Charger et exécuter du code javascript de manière synchrone

Existe-t-il un moyen de charger et d’exécuter un fichier javascript de manière synchrone, comme un XMLHttpRequest synchrone?

J'utilise actuellement une synchronisation XMLHttpRequest puis une évaluation pour cela, mais le débogage de ce code est très difficile ...

Merci de votre aide!

Mettre à jour

J'ai essayé ça maintenant:

test.html

<html>
    <head>
        <script type="text/javascript">
            var s = document.createElement("script");
            s.setAttribute("src","script.js");
            document.head.appendChild(s);
            console.log("done");
        </script>
    </head>
    <body>
    </body>
</html>

script.js

console.log("Hi");

Sortie: Fait Salut

Donc, il n'a pas été exécuté de manière synchrone. Une idée pour faire apparaître "Hi" en premier?

Update 2 Autre exemple

test.html (code à l'intérieur d'une balise de script)

var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();

script.js

function SayHi(){
    console.log("hi");
}

Sortie: Uncaught ReferenceError: SayHi n'est pas défini

31
Van Coding

Si vous utilisez ceci:

function loadScriptSync (src) {
    var s = document.createElement('script');
    s.src = src;
    s.type = "text/javascript";
    s.async = false;                                 // <-- this is important
    document.getElementsByTagName('head')[0].appendChild(s);
}

Vous pouvez faire ce que vous voulez (bien que divisé dans un fichier script supplémentaire)

test.html (code dans une balise de script):

loadScriptSync("script.js");
loadScriptSync("sayhi.js"); // you have to put the invocation into another script file

script.js :

function SayHi() {
     console.log("hi");
}

sayhi.js :

SayHi();
19
heinob

Tous les scripts chargés une fois que DOM est prêt sont chargés de manière asynchrone. La seule raison pour laquelle le navigateur les charge de manière synchrone est la fonction write qui peut générer quelque chose. Ainsi, vous pouvez utiliser le rappel onload de l'élément script pour obtenir ce que vous voulez.

var s = document.createElement("script");
s.setAttribute("src","script.js");
s.onload = function(){
    console.log('Done');
}
document.head.appendChild(s);

Une autre méthode consiste à charger le fichier js via XHR et à définir le code dans l'élément de script:

window.onload = function(){
    var req = new XMLHttpRequest();
    req.open('GET', "test.js", false);
    req.onreadystatechange = function(){
        if (req.readyState == 4) {
            var s = document.createElement("script");
            s.appendChild(document.createTextNode(req.responseText));
            document.head.appendChild(s);
        }
    };
    req.send(null);
}
13
bjornd

D'une question similaire ( https://stackoverflow.com/a/3292763/235179 ):

<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"><\/script>');
</script>

<script type="text/javascript">
  functionFromOther();
</script>

Soit le code appelé depuis le script document.write 'd doit être dans son propre <script>, soit dans l'événement window.onload().

10
Josh Johnson

Vos scripts s'exécutent de manière synchrone

votre code si mis ensemble est:

1. create script element
2. set its attribute src
3. set its attribute deferred
4. display done...

cette première partie arrête l'exécution et la transmet au script suivant

5. script executes and displays Hi

Tout est très synchrone ... En Javascript, une partie du code est exécutée jusqu'à ce qu'elle soit exécutée jusqu'à la dernière ligne ou transmise à des systèmes internes (comme XHR ou une minuterie).

Quand on veut préparer certaines parties à exécuter plus tard, on le prépare avec setTimeout. Même si le délai d'attente est plus court que le reste du code prendra, c'est le temps qu'il sera exécuté. Après l'exécution du code. Exemple:

// some code
setTimeout(function(){ alert("I'm second alert"); }, 1);
longExecutionTask();
alert("I'm the first alert");

Dans le code ci-dessus, même si setTimeout est défini pour s'exécuter après 1 ms, il ne commencera pas tant que le code ne sera pas terminé, ce qui se terminera par l'affichage d'une boîte alert. La même chose se passe dans votre cas. Le premier lot de code doit être exécuté avant de pouvoir commencer.

Pourquoi vous obtenez une exception (dans l'exemple 2)

Vous avez ajouté un peu plus de code après avoir écrit ma réponse, voici donc quelques informations supplémentaires.

L'ajout d'une balise de script ne l'exécutera pas immédiatement. Le chargement du script + l'exécution auront lieu lorsque l'analyseur HTML obtiendra l'élément SCRIPT que vous avez ajouté. Il le chargera à ce moment-là et évaluera/exécutera son contenu.

  1. L'analyseur HTML commence à analyser votre document
  2. HEAD est en cours d'analyse et sa balise enfant SCRIPT est analysée et exécutée. Cette exécution ajoute un élément supplémentaire à la balise BODY qui n'a pas encore été analysée.
  3. L'analyseur passe à BODY et analyse son contenu (la balise SCRIPT récemment ajoutée) qui charge ensuite le script et exécute son contenu.

Les éléments SCRIPT sont immédiatement exécutés uniquement lorsque vous les ajoutez après l'analyse de votre page et son rendu dans le navigateur. Dans votre cas, ce n'est pas le cas. Le premier script s’exécute immédiatement et celui qui est ajouté dynamiquement s’exécute lorsque les analyses lui parviennent.

5
Robert Koritnik

Vous pouvez synchroniser des opérations asynchrones entre eux. Crée une fonction récursive pour représenter une boucle et appelle l'opération suivante à la fin de l'opération précédente. La fonction suivante importe les scripts dans l'ordre avec la même technique. Il attend qu'un script soit chargé et s'il n'y a pas d'erreur, continue avec le suivant. Si une erreur survient, elle appelle la fonction de rappel avec l'événement error et s'il n'y a pas d'erreur, appelle la même fonction de rappel avec la valeur null une fois tous les scripts chargés. Il nettoie également après lui-même avec s.parentNode.removeChild(s).

function importScripts(scripts, callback) {
    if (scripts.length === 0) {
        if (callback !== undefined) {
            callback(null);
        }
    }
    var i = 0, s, r, e, l;
    e = function(event) {
        s.parentNode.removeChild(s);
        if (callback !== undefined) {
            callback(event);
        }
    };
    l = function() {
        s.parentNode.removeChild(s);
        i++;
        if (i < scripts.length) {
            r();
            return;
        }
        if (callback !== undefined) {
            callback(null);
        }
    };
    r = function() {
        s = document.createElement("script");
        s.src = scripts[i];
        s.onerror = e;
        s.onload = l;
        document.head.appendChild(s);
    };
    r();
}
0
User0123456789