2012-03-14 9 views
9

estoy tratando carga de algunos scripts de forma dinámica con jQuery:jQuery: guiones de carga con el fin

var scripts = ['script1.js','script2.js','script3.js']; 

$.each(scripts , function(i, val) { 
    $.getScript(val, function() { 
    console.log('loaded '+ val); 
}); 

Pero a veces el orden de las secuencias de comandos cambios cargados. ¿Cómo puedo cargar cada script después de que el anterior se haya cargado correctamente?

Respuesta

16

que es posible cargar cada carga después de que el anterior ha terminado utilizando la función de devolución de llamada de $.getScript() como una llamada de función recursiva.

//setup array of scripts and an index to keep track of where we are in the process 
var scripts = ['script1.js','script2.js','script3.js'], 
    index = 0; 

//setup a function that loads a single script 
function load_script() { 

    //make sure the current index is still a part of the array 
    if (index < scripts.length) { 

     //get the script at the current index 
     $.getScript(scripts[index], function() { 

      //once the script is loaded, increase the index and attempt to load the next script 
      console.log('Loaded: ' + scripts[index]); 
      index++; 
      load_script(); 
     }); 
    } 
} 

lo que está ocurriendo en su código es que los guiones se están solicitando al mismo tiempo, y ya que se cargan de forma asíncrona, regresan y ejecutar en un orden aleatorio.

actualización

No he probado esto, pero si las secuencias de comandos están alojados localmente, entonces se podría tratar de recuperarlos en texto plano, a continuación, almacenar todo el código en las variables hasta que todos se cargan en el cual tiempo que podría evaluar las secuencias de comandos en orden:

var scripts = ['script1.js','script2.js','script3.js'], 

    //setup object to store results of AJAX requests 
    responses = {}; 

//create function that evaluates each response in order 
function eval_scripts() { 
    for (var i = 0, len = scripts.length; i < len; i++) { 
     eval(responses[scripts[i]]); 
    } 
} 

$.each(scripts, function (index, value) { 
    $.ajax({ 
     url  : scripts[index], 

     //force the dataType to be `text` rather than `script` 
     dataType : 'text', 
     success : function (textScript) { 

      //add the response to the `responses` object 
      responses[value] = textScript; 

      //check if the `responses` object has the same length as the `scripts` array, 
      //if so then evaluate the scripts 
      if (responses.length === scripts.length) { eval_scripts(); } 
     }, 
     error : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ } 
    }); 
}); 
+0

Ahh, ninja'd. Buen trabajo sin embargo. –

+0

¡esto parece estar funcionando! ¡Gracias y muy buenas explicaciones! – greenbandit

0

se puede ordenar() la matriz -

var sorted = scripts.sort(); 

y luego usar ordenados en su cada función.

+0

Creo que la pregunta de los OP es sobre el orden de las respuestas de las solicitudes de AJAX. – Jasper

1

Algunas secuencias de comandos pueden variar en tamaño, por lo tanto es impredecible. Prueba algo como esto.

var scripts = ['script1.js','script2.js','script3.js'], ScriptIndex = 0; 
function LoadScript(index){ 
    if(index >= scripts.length) 
     return; 

    $.getScript(scripts[index], function(){ 
     console.log('Loaded script '+ scripts[index]); 
     LoadScript(++ScriptIndex); 
    } 
} 

Esto debería cargar cada script después de que el último se haya cargado por completo. Asegúrese de que se inicia fuera llamando a la función LoadScript(0);

+0

¿Cuál es la diferencia entre '++ ScriptIndex' y' ScriptIndex ++' (si hay alguno)? – Jasper

+0

'++ ScriptIndex' establece Y devuelve el valor incrementado, mientras que' ScriptIndex ++ 'simplemente establece el valor incrementado. –

+1

gotcha, gracias. – Jasper

10

Haces hacer uso del hecho de la jqXhr object devuelto por $.getScript (y todos los demás métodos Ajax) implementa la interfaz Promise y por lo tanto proporciona .pipe() que puede ser utilizado para objetos cadena diferido :

var deferred = new $.Deferred(), 
    pipe = deferred; 

$.each(scripts , function(i, val) { 
    pipe = pipe.pipe(function() { 
     return $.getScript(val, function() { 
      console.log('loaded '+ val); 
     }); 
    }); 
}); 

deferred.resolve(); 

Para obtener más información, echar un vistazo a deferred objects y deferred.pipe.

En general, el uso de objetos diferidos le da mayor flexibilidad y podría permitir añadir controladores de errores con mayor facilidad.

+0

Desde que aprendí acerca de los diferidos, los amo. Pero de alguna manera me perdí la función de tubería. ¡Buena publicación! – roberkules

+0

Esto es inútil: básicamente estás haciendo '$ .when ($ .getScript (a), $ .getScript (b))' - los 'scripts' aún se evalúan justo después de que se cargan desde el servidor, independientemente de si el anterior ya ha sido descargado o no. – Dwelle

+0

@Dwellee: No, ese no es el caso. '$ .getScript (b)' se llama dentro de la devolución de llamada '.pipe', que solo se invoca después de descargar' $ .getScript (a) '(ya sea que se haya evaluado, no estoy seguro). –

2

Una versión mejorada de @ solución de Jasper:

  • usando $.when para sincronizar las llamadas.
  • utilizando un eval global.

Aquí está el código:

/** 
* Load scripts in parallel keeping execution order. 
* @param {array} An array of script urls. They will parsed in the order of the array. 
* @returns {$.Deferred} 
*/ 
function getScripts(scripts) { 
    var xhrs = scripts.map(function(url) { 
     return $.ajax({ 
      url: url, 
      dataType: 'text', 
      cache: true 
     }); 
    }); 

    return $.when.apply($, xhrs).done(function() { 
     Array.prototype.forEach.call(arguments, function(res) { 
      eval.call(this, res[0]); 
     }); 
    }); 
} 

Esta GIST: https://gist.github.com/ngryman/7309432.

Cuestiones relacionadas