Solución:
Bien, setTimeout
, según su definición, no detendrá el hilo. Esto es deseable, porque si lo hiciera, congelaría toda la interfaz de usuario durante el tiempo que estuvo esperando. si realmente necesitas usar setTimeout
, entonces deberías usar funciones de devolución de llamada:
function myfunction() {
longfunctionfirst(shortfunctionsecond);
}
function longfunctionfirst(callback) {
setTimeout(function() {
alert('first function finished');
if(typeof callback == 'function')
callback();
}, 3000);
};
function shortfunctionsecond() {
setTimeout('alert("second function finished");', 200);
};
Si usted es no utilizando setTimeout
, pero solo tienen funciones que se ejecutan durante mucho tiempo y estaban usando setTimeout
para simular eso, entonces tus funciones haría en realidad sea sincrónico, y no tendría este problema en absoluto. Sin embargo, debe tenerse en cuenta que las solicitudes AJAX son asincrónicas y, al igual que setTimeout
, no detenga el hilo de la interfaz de usuario hasta que haya terminado. Con AJAX, como con setTimeout
, tendrá que trabajar con devoluciones de llamada.
Vuelvo a estas preguntas después de todo este tiempo porque me tomó tanto tiempo encontrar lo que creo que es una solución limpia: la única forma de forzar una ejecución secuencial de JavaScript que conozco es usar promesas. Hay explicaciones exhaustivas de las promesas en: Promises / A y Promises / A +
La única biblioteca que implementa las promesas que conozco es jquery, así que aquí es cómo resolvería la pregunta usando las promesas de jquery:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function myfunction()
{
promise = longfunctionfirst().then(shortfunctionsecond);
}
function longfunctionfirst()
{
d = new $.Deferred();
setTimeout('alert("first function finished");d.resolve()',3000);
return d.promise()
}
function shortfunctionsecond()
{
d = new $.Deferred();
setTimeout('alert("second function finished");d.resolve()',200);
return d.promise()
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
Al implementar una promesa y encadenar las funciones con .then (), se asegura de que la segunda función se ejecutará solo después de que se haya ejecutado la primera.Es el comando d.resolve () en longfunctionfirst () el que da la señal para iniciar la siguiente función.
Técnicamente, el shortfunctionsecond () no necesita crear un diferido y devolver una promesa, pero me enamoré de las promesas y tiendo a implementar todo con promesas, lo siento.
Soy un experto en programación y recientemente volví a mi antigua pasión y estoy luchando por encajar en este nuevo mundo brillante orientado a objetos, impulsado por eventos y, aunque veo las ventajas del comportamiento no secuencial de Javascript, hay momentos en los que realmente se consiguen. en el camino de la sencillez y la reutilización. Un ejemplo simple en el que he trabajado fue tomar una foto (teléfono móvil programado en javascript, HTML, phonegap, …), redimensionarla y subirla a un sitio web. La secuencia ideal es:
- Toma una foto
- Cargue la foto en un elemento img
- Cambiar el tamaño de la imagen (usando Pixastic)
- Subirlo a un sitio web
- Informar al usuario sobre el éxito y el fracaso
Todo esto sería un programa secuencial muy simple si tuviéramos cada paso devolviendo el control al siguiente cuando esté terminado, pero en realidad:
- Tomar una foto es asincrónica, por lo que el programa intenta cargarla en el elemento img antes de que exista
- La carga de la foto es asincrónica, por lo que la imagen de cambio de tamaño comienza antes de que la imagen se cargue por completo
- El cambio de tamaño es asincrónico, por lo que la carga al sitio web comienza antes de que la imagen cambie de tamaño por completo.
- La carga al sitio web es asíncrona, por lo que el programa continúa antes de que la foto se cargue por completo.
Y por cierto, 4 de los 5 pasos involucran funciones de devolución de llamada.
Por lo tanto, mi solución es anidar cada paso en el anterior y usar .onload y otras estratagemas similares, se ve así:
takeAPhoto(takeaphotocallback(photo) {
photo.onload = function () {
resizePhoto(photo, resizePhotoCallback(photo) {
uploadPhoto(photo, uploadPhotoCallback(status) {
informUserOnOutcome();
});
});
};
loadPhoto(photo);
});
(Espero no haber cometido demasiados errores al llevar el código a lo esencial, lo real distrae demasiado)
Creo que este es un ejemplo perfecto donde la asincrónica no es buena y la sincronización es buena, porque al contrario que el manejo de eventos de Ui, debemos tener cada paso terminado antes de que se ejecute el siguiente, pero el código es una construcción de muñeca rusa, es confuso e ilegible. la reutilización del código es difícil de lograr debido a todo el anidamiento, es simplemente difícil llevar a la función interna todos los parámetros necesarios sin pasarlos a cada contenedor a su vez o usar variables globales malvadas, y me hubiera encantado que el resultado de todo este código me daría un código de retorno, pero el primer contenedor estará terminado mucho antes de que el código de retorno esté disponible.
Ahora, para volver a la pregunta inicial de Tom, ¿cuál sería la solución inteligente, fácil de leer y fácil de reutilizar para lo que hubiera sido un programa muy simple hace 15 años usando, digamos C, y una placa electrónica tonta?
De hecho, el requisito es tan simple que tengo la impresión de que debo estar perdiendo una comprensión fundamental de Javsascript y la programación moderna. Seguramente la tecnología está destinada a impulsar la productividad, ¿no?
Gracias por su paciencia
Raymond el dinosaurio 😉