Soy asincrono despues de 0 milisegundos

Posiblemente alguno  puede seguir pensando que escribir un Promise es hacer su código Javascript asíncrono. Bueno pues si piensas eso ya te digo yo que no.

Promise no es más que un mecanismo para hacer nuestro código más legible y de esa forma evitar los tediosos callback que hasta el momento hemos utilizado.

Bueno como siempre vamos a empezar con un ejemplo para demostrar que Promise no es asíncrono.

function promise() {
return new WinJS.Promise(function (complete, error, progress) {
try {
var i = 0;
for (i = 0; i < 10; i++) {
progress(i);
}
complete(i);
}
catch (ex) {
error(ex);
}
});
}
function runPromise() {
var result = promise().then(
function (data) {
console.log(data);
},
function (progress) {
console.log(progress);
},
function (error) {
console.log(error);
});

}
runPromise();
Si analizamos este código la respuesta inmediata sería, la salida por consola nos mostrará  la siguiente secuencia 0,1,2,3,4,5,6,7,8,9 y por último 10. La respuesta es por consola solamente vamos a ver “10”, es decir la ejecución de complete, pero nunca progress.
 
Ante esto la pregunta  ¿Si progress se ejecuta y no es “undefined”, porque no escribe en la consola el valor de i?. Pues sencillo o creo que más bien complicado:).
 
Cuando ejecutamos el constructor de una Promise pasan varias cosas.
 
1. Se pasa al contructor una función anónima que recibe tres parámetros “complete,error,progress” y se ejecuta.
 
2. Ninguno de los tres parametros apunta en realidad a las funciones que he pasado como parametros  a la función then. Puesto que aún no se ha ejecutado, sino a “complete,error,progress” de “PromiseStateMachine” una clase que se crea en base.js de la que deriva “Promise”.
 
3. ¿Y por qué se ejecuta “complete” y no “progress”? Pues por eso por que Javascript es “single-threaded”. Realmente la línea de código siguiente “complete(i)” no hace lo que creemos , sino asignar un valor “10”  al objeto Promise que hemos creado.
 
4. Bueno ¿Y entonces porque ejecuta lo siguiente?
 
function (data) {
console.log(data);
},
 
Porque al ejecutar “then” después de nuestra función anónima nuestra Promise ha realizado internamente lo suficiente como para que “then” sea un objeto del tipo “CompletePromise” y llama a la función “then” de este, ¿queréis ver  el código? 🙂
 
try {
// If the value returned from the completion handler is the same as the value
// provided to the completion handler then there is no need for a new promise.
//
var newValue = onComplete ? onComplete(this._value) : this._value;
return newValue === this._value ? this : new CompletePromise(newValue);
} catch (ex) {
return new ExceptionPromise(ex);
}

En la primera linea se ve claramente que se llama a “onComplete”,  función que escribe en la consola nuestro famoso “10”. De lo cual podemos deducir que primero se ejecuta nuestro bucle y después “then”, sino os convence podéis cambiar el valor 10 por 100000000 y ya os digo yo que os vais a esperar un poquito o más bien mucho:).
 
Bueno después de este tedioso rollo, quizá alguien se pregunte para que quiero utilizar Promise, bueno mi conclusión es sencilla como dije nos ayuda a estructurar nuestro código de mejor forma, cosa que no implica que mi código sea asíncrono. Queda claro no:).
 
Queréis el mismo código asíncrono, entre comillas:), bueno pues otra función anónima que ejecute nuestro bucle pero con “setTimeout”.
 
function promise() {
return new WinJS.Promise(function (complete, error, progress) {
var id;
id = setTimeout(function () {
try{
for (var i = 0; i < 10; i++) {
progress(i);
}
complete(i);
}
catch (ex) {
error(ex);
}
finally {
if (id) {
clearTimeout(id);
}
}
}, 0);
});
}
function runPromise() {
promise().then(
function (data) { console.log(data); },
function (progress) { console.log(progress); },
function (error) { console.log(error); }
);
}
runPromise();

Y a estás alturas alguien puede pensar y porque el titulo de este post, pues porque por casualidades de la vida ayer me encontré con esta otra entrada que es digna de leer y yo paso un 0 a setTiemout:).

setImediate Api

Me tome la molestia de escribir este script y probarlo en Chrome,FireFox e IE9 y la verdad que me sorprendió, bastante que Chrome sea el más lento en ejecutar callback por segundosSonrisa

var i = 0,
id,
endDate,
startDate = new Date().getTime(),
ckeckEnd = function () {
endDate = new Date().getTime();
var result = (endDate - startDate)
if (result >= 1000) {
if (id) clearInterval(id)
console.log(result + " " + i);

}
else {
i++;
}

};
id = setInterval(function () {
ckeckEnd();
}, 1);

Conclusion:

Que todo esto es un mundo desconocido para los que venimos de c# y que realmente explorarlo es toda una satisfacción, aunque podemos decir que Javascript tiene mucho, pero mucho que mejorarSonrisa

 

4 comentarios sobre “Soy asincrono despues de 0 milisegundos”

  1. Hola Pedro solo dos cosillas, el primer ejemplo lo tiens al reves si es asi como lo has realizado normal que no funcione.
    El segundo apunte es que con WinRT Promise no es opcional lo utilizan la mayoría de funciones que interactuan con el sistema. Solo tienes que acceder a un dispositivo como la camara de fotos para ver como la ejecucíón de la aplicación continua y solo recuperas el fichero cuando el dipositivo ha capturado la imagen.

    var dialogo = Windows.Media.Capture.CameraCaptureUI();
    dialogo.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function (file) {

    if (file) {
    var photoBlobUrl = URL.createObjectURL(file);
    document.getElementById(«capturedPhoto»).src = photoBlobUrl;
    }
    });

    Saludos.

  2. Hola Marc,

    Lo primero gracias por el comentario. Estoy de acuerdo con lo que comentas, pero como bien sabes las funciones tal y como ha comentado @pablonete por twitter hacen lo mismo. Es decir el error está pero si te fijas en este código las funciones son anonimas.

    function runPromise() {
    var result = promise().then(
    function (data) {
    console.log(data);
    },
    function (progress) {
    console.log(progress);
    },
    function (error) {
    console.log(error);
    });

    }

    Con lo cual que más da que escriba la primera o la segunda, todas hacen lo mismo y son 3:).

    Respecto a lo de WinRT, entiendo que no sea opcional, pero mi mensaje es claro. No es Promise quien hace que tú código sea asincrono, ese es el mensaje de este post. Es asincrono, porque captureFileAsync es asincrono:).

    Ahora que se haya decidido utilizar el patrón Promise en vez de los callback. me parece estupendo.

    Pero creo que coincidimos que javascript no es asincrono y que promise no hace este asincrono. Estamos de acuerdo:)

    Saludos,

  3. Promise no pretende hacer Javascript asincrono, porque Promise es una implementación del patrón «observable» muy util para gestionar las llamadas asíncronas.

    Gestionar y hacer asincronismo son cosas diferentes

    Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *