2011-01-23 16 views
12

Tengo una función javascript que comprueba para ver si existe un artista en un archivo XML:Javascript no salir de la función

function artistExists(artist) { 
// get data from artists.xml 
$('.loading').show(); 
$.get(artists_xml, function(xml){ 
    $('.loading').hide(); 
    $(xml).find('artist').each(function(){ 
     if ($(this).find("ar_artist").text() == artist.val()) { 
      alert ('artist exists'); 
      return true; 
     } //end if 
    }); // end each 
    alert ('artist does not exist'); 
    return false; 
}); // end .get function 
} // end of artistExists function 

Estoy en lo cierto al pensar que el 'return true' línea debe dejar de ejecución de la función? Pensé que sí, pero después de encontrar un registro y ejecutar la primera ejecución de alerta continúa a la alerta de falla en la parte inferior.

¿Qué estoy haciendo mal por favor? Gracias.

Respuesta

14

Devuelve false, en lugar de true, para finalizar el ciclo each; desde the docs:

Podemos detener el bucle desde la función de devolución de llamada devolviendo false.

Eso simplemente terminará su lazo each, no es la función general. Deberá establecer una bandera para saber si encontró algo, p. algo como esto:

function artistExists(artist) { 
// get data from artists.xml 
$('.loading').show(); 
$.get(artists_xml, function(xml){ 
    var found = false; // <== Added 
    $('.loading').hide(); 
    $(xml).find('artist').each(function(){ 
     if ($(this).find("ar_artist").text() == artist.val()) { 
      alert ('artist exists'); 
      found = true; // <== Added 
      return false; // <== Modified 
     } //end if 
    }); // end each 
    if (!found) {   // <== Added 
     alert ('artist does not exist'); 
    }      // <== Added 
    return found;   // <== Modified 
}); // end .get function 
} // end of artistExists function 
+0

Ha pasado mucho tiempo, pero tengo una pregunta al respecto: traté de usar 'return' solamente y detuvo el' .each', así que 'return false' no es algo que debe hacer o hay algo ¿Yo deberia saber? –

+1

@CagatayUlubay: Simplemente 'return' no detendrá el ciclo' each', simplemente salta de la devolución de llamada para esa iteración; el ciclo continuará con la siguiente iteración. 'return false' saltará de la devolución de llamada para esa iteración ** y ** stop looping. –

14

Sí, hace "salir" de la ejecución de la función. La pregunta es, "¿qué función?" En este caso, la respuesta debería ser bastante clara: es la función pasada al .each().

Puede finalizar el comportamiento de bucle de .each() devolviendo false en lugar de true, pero eso no lo sacará de la función externa. Lo que probablemente debería considerar es configurar una variable local en la función externa y configurar la función interna cuando encuentre algo (y luego romper el ciclo .each()). Luego, la función principal puede verificar la variable local para ver si se configuró.

Este es un caso en el que realmente me gustaría usar una API .reduce() o .inject(), pero jQuery no tiene una y realmente se oponen a ella.

+0

Gracias Pointy, funciona, aunque parece un poco raro, ¿no? Sería genial si pudiéramos poner números después de una declaración de interrupción. – RichJohnstone

+0

Bueno, el problema es que cuando sus funciones son valores de primera clase como en JavaScript, la disposición "estática" del código realmente no le dice mucho sobre cómo/cuándo/dónde se llamará realmente una función. – Pointy

4

$.get es una función asíncrona, es decir, la función principal, artistExists se devolverá inmediatamente, y se iniciará una solicitud GET. Para poder obtener el resultado, necesitará una devolución de llamada.

function artistExists(artist, cb) { 
    $('.loading').show(); 
    $.get(artists_xml, function(xml) { 

     var found = false; 

     $('.loading').hide(); 

     $(xml).find('artist').each(function(){ 
      if ($(this).find("ar_artist").text() == artist.val()) { 
       found = true; 
       return false; // use return false to stop .each() 
      } 
     }); 

     // the built in action. 
     if (found) { 
      alert ('artist exists'); 
     } else { 
      alert ('artist does not exist'); 
     } 

     // call the callback function 
     cb (found); 

    }); 
} 

Luego, para usar, necesita usar una función de devolución de llamada. De

var isExists = artistExists('lol'); 
// do stuff 

Es necesario cambiarlo a:

artistExists('lol', function(isExists) { 
    // do stuff 
}); 
+0

Gracias por este tailandes, en refection este es obviamente el camino a seguir. Simplemente no entiendo muy bien cómo usarlo en mi código, soy nuevo y nunca he usado una devolución de llamada antes. Quería poder tener una línea de código como "if (artistExists ($ ('# artistfield'))) {// do stuff}". ¿Cómo voy a hacer esto con el negocio de devolución de llamada, por favor? Muchas gracias. – RichJohnstone

+0

Una función asíncrona significa una función que no puede obtener el resultado instantáneamente cuando llama. Una función de devolución de llamada es importante para que pueda recibir una notificación cuando el resultado esté disponible. Si echa un vistazo, la función 'artistExists' acepta otro argumento' cb', y 'cb' se llama después de que tengamos el resultado en' cb (found) '. – Thai

+0

gracias otra vez tailandés. Entiendo que la naturaleza asíncrona de la solicitud significa que tengo que esperar el resultado. Lo que no tengo claro es cómo uso mi función cb/callback para pasar el verdadero/falso a mi línea de código de llamada original. Si pudieran ayudarme con un poco de código aquí, estaría muy agradecido. gracias de nuevo. – RichJohnstone

1

Gracias por todos los consejos. Al final decidí que necesitaba una llamada sincrónica, así que hice la siguiente nueva versión de la función .get, llamado .sget:

jQuery.extend({ 
sget: function(url, callback, type) { 
     return jQuery.ajax({ 
      type:  "GET", 
      url:  url, 
      success: callback, 
      async:  false, 
      dataType: type 
     }); 
    } 
}); 

El 'asíncrono: false' par de opciones de los 'ajax' hace que el llamar sincrónicoA continuación, la siguiente edición de mi función falla el original:

function artistExists(artistname) { 
var found = false; 
console.log("From Input:Artist= " + artistname.val()); 
// get data from artists.xml 
$('.loading').show(); 
$.sget(artists_xml, function(xml){ // new synchronous get 
    $('.loading').hide(); 
    $(xml).find('artist').each(function(){ 
     if ($(this).find("ar_artist").text() == artistname.val()) { 
      console.log('From File:Artist= ' + $(this).find("ar_artist").text()); 
      found = true; 
      console.log("In each loop:Flag= " + found); 
      return; 
     } //end if 
    }); // end each 
}); // end .get function 
console.log("At end:Flag= " + found); 
return found; 

}

serán removidos Las líneas console.log. Sin embargo, muestran que las cosas están sucediendo en el orden que quiero. ASÍ, la nueva función .sget síncrona y el uso de una bandera 'encontrada', como se indicó anteriormente, han hecho el truco para mí. No sé por qué no pude pensar en hacer esto ayer.

Gracias a todos.

Cuestiones relacionadas