functions - javascript generators
Comprender el flujo de código con rendimiento/generadores (2)
Aparentemente, yield es azúcar sintáctica para envolver a qué vuelve en una devolución de llamada y asignar el valor del resultado de manera apropiada (y al menos en el caso de co, lanzar el argumento de error a la devolución de llamada)
No, el yield
no es azúcar sintáctico. Es el elemento de sintaxis central de los generadores. Cuando se crea una instancia de ese generador, puede ejecutarlo (invocando .next()
en él), y eso devolverá el valor que fue return
o yield
. Cuando se yield
el generador, puede continuar más tarde al llamar a .next()
nuevamente. Los argumentos a next
serán el valor que devuelve la expresión de rendimiento dentro del generador.
Solo en el caso de co
, esas cosas de devolución de llamada asincrónica (y otras cosas ) se manejan "apropiadamente" para lo que se consideraría natural en una biblioteca de flujo de control asíncrono.
¿Qué aspecto tiene el hecho cuando se utiliza el rendimiento?
El ejemplo de función de thread
del artículo que lees te da una buena impresión de esto:
function thread(fn) {
var gen = fn();
function next(err, res) {
var ret = gen.next(res);
if (ret.done) return;
ret.value(next);
}
next();
}
En su código, yield
produce el valor de la expresión read("file")
del generador cuando se ejecuta. Esto se convierte en la ret.val
, el resultado de gen.next()
. A esto, se pasa la next
función: una devolución de llamada que continuará el generador con el resultado que se le pasó. En el código de su generador, parece que la expresión de yield
devuelve este valor.
Una versión "desenrollada" de lo que sucede podría escribirse así:
function fn*() {
console.log( yield function (done) {
fs.readFile("filepath", "file", done);
} );
}
var gen = fn();
var ret1 = gen.next();
var callasync = ret1.value;
callasync(function next(err, res) {
var ret2 = gen.next(res); // this now does log the value
ret2.done; // true now
});
He leído varios ejemplos de código usando generadores de JavaScript como este . El bloque de uso de generador más simple que puedo encontrar es algo así como:
function read(path) {
return function (done) {
fs.readFile(path, "file", done);
}
}
co(function *() {
console.log( yield read("file") );
})();
Esto realmente imprime el contenido del file
, pero mi hangup es donde se llama done
. Aparentemente, yield es azúcar sintáctica para ajustar lo que devuelve en una devolución de llamada y asignar el valor de resultado de manera apropiada (y al menos en el caso de co
, lanzar el argumento de error a la devolución de llamada). ¿Mi comprensión de la sintaxis es correcta?
¿Qué aspecto tiene el done
cuando se utiliza el yield
?
Publiqué una explicación detallada de cómo funcionan los generadores aquí .
En una forma simplificada, su código podría verse así sin co
(no probado):
function workAsync(fileName)
{
// async logic
var worker = (function* () {
function read(path) {
return function (done) {
fs.readFile(path, "file", done);
}
}
console.log(yield read(fileName));
})();
// driver
function nextStep(err, result) {
try {
var item = err?
worker.throw(err):
worker.next(result);
if (item.done)
return;
item.value(nextStep);
}
catch(ex) {
console.log(ex.message);
return;
}
}
// first step
nextStep();
}
workAsync("file");
La parte del controlador de workAsync
itera de workAsync
asíncrona a través del objeto del generador, llamando a nextStep()
.