nodejs node generators generadora functions funcion ecmascript await async javascript node.js generator yield

node - yield javascript



Generadores de Javascript: entendiéndolos (3)

Estoy bastante seguro de que mi comprensión de los generadores está intrínsecamente dañada. Todos los recursos en línea parecen estar en conflicto y se convierten en una experiencia de aprendizaje increíblemente difícil y confusa.

Por lo que entiendo, la palabra clave de yield permite que un bloque de código actualmente en ejecución espere un valor en lugar de lanzar el código restante para que se ejecute dentro de una devolución de llamada. Entonces, como la mayoría de los tutoriales han señalado, puedes usar esto:

(function *() { // Wait until users have be got and put into value of `results` var results = yield db.get("users"); // And continue view.display(results); })();

En lugar de:

db.get("user", function(results) { view.display(results); });

Bien, todo está bien hasta que intento escribir mis propios generadores. Me he topado con varios enganches:

  • El primer código de ejemplo I anterior no se ejecutará porque no hay nada que iterar sobre el generador, ¿correcto? Algún ser superior tiene que llamar al. .next algún lugar, ¿verdad?
  • La API completa deberá reescribirse hasta las llamadas de E / S para que sean compatibles con los generadores, ¿correcto?
  • De lo que reconozco, el yield parece esperar el valor de la mayoría de los casos de uso general, mientras que en la parte de la implementación (leer: devolver el valor a / dentro de db.get ) el yield parece devolver el valor al bloque actualmente en espera para reanudarse ejecución

Tomar como ejemplo:

function *fn() { yield 1; yield "a"; } var gen = fn(); gen.next(); // 1 gen.next(); // "a";

yield en ese contexto es enviar valores de nuevo hacia abajo en lugar de esperar los resultados. En el primer ejemplo anterior, espera los resultados de db.get y reanuda la ejecución en lugar de "devolver" o devolver un valor. Si el caso db.get es verdadero, ¿no es esto inherentemente síncrono? Quiero decir, no es exactamente lo mismo que:

(function() { //Wait for the results var results = fs.readFileSync("users.txt"); // Use results view.display(results); })();

Desafortunadamente, si queda claro de esta pregunta (probablemente lo único claro) es que no entiendo a los generadores. Con suerte, podría tener una idea aquí.


Los dos ejemplos no son los mismos. Cuando cede, la función ahora se convierte efectivamente en una devolución de llamada, a la espera de que se ejecute cuando finalice db.get ("usuarios"). De esta manera, la función no bloquea la ejecución de otra función. Piense en ello como una manera de convertir las funciones síncronas en funciones asíncronas al hacerle saber al sistema que puede hacer una pausa en ciertos puntos.


Nada de lo asíncrono si forma parte de los generadores. Los generadores simplemente hacen una pausa y reanudan los bloques de código. toda la magia asíncrona ocurre cuando usas lo que yo llamo un "motor generador" como co .

básicamente, lo que hace gen.next() es devolver el último valor ed de yield y le permite devolver un valor si el yield se asigna a algo, ej. var something = yield 1 . así que si tienes el bloque de código:

function* genfun() { var a = yield 1 var b = yield 2 } var gen = genfun() gen.next() // returns the first yielded value via `{value: 1}` gen.next(1) // sets `a` as 1, returns the next yielded value via `{value: 2}` gen.next(2) // sets `b` as 2, the generator is done, so it returns `{done: true}`

gen.throw(err) es el mismo que el siguiente, excepto que el error se produce en lugar de asignarse a una variable.

Así es como funcionan los motores de flujo de control: obtienes el siguiente valor que probablemente sea una devolución de llamada o algo así. ejecute la devolución de llamada y no gen.next() hasta que gen.next() la devolución de llamada.


TL; DR: la esencia del generador es controlar la suspensión de la ejecución del código.

Para generador en sí, puede referirse a esto .

En resumen, hay tres componentes que debe distinguir: 1. función del generador 2. generador 3. resultado generado

La función del generador es simplemente la function con estrella en la cabeza y (opcional) yield en su cuerpo.

function *generator() { console.log(''Start!''); var i = 0; while (true) { if (i < 3) yield i++; } } var gen = generator(); // nothing happens here!!

La función del generador en sí no hace nada más que devolver un generador, en el caso anterior, gen . No hay salida de consola aquí porque solo después de que se llame al next método del generador devuelto , se ejecutará la función de cuerpo del generador . El generador tiene varios métodos, de los cuales el más importante es el next . next ejecuta el código y devuelve el resultado del generador .

var ret = gen.next(); // Start! console.log(ret); // {value: 0, done: false}

ret es el resultado del generador . Tiene dos propiedades: value , el valor que se obtiene en la función del generador , y done , un indicador que indica si la función del generador regresa.

console.log(gen.next()); // {value: 1, done: false} console.log(gen.next()); // {value: 2, done: false} console.log(gen.next()); // {value: undefined, done: true}

En este punto, nadie esperará que usted entienda el generador, al menos no la potencia asíncrona del generador.

Para ponerlo simple, el generador tiene dos características:

  • uno puede elegir saltar de una función y dejar que el código externo determine cuándo saltar de nuevo a la función.
  • el control de la llamada asíncrona se puede hacer fuera de su código

En el código, el yield salta fuera de la función, y next(val) vuelve a la función y pasa el valor nuevamente a la función. El código externo puede manejar llamadas asíncronas y decidir el momento adecuado para cambiar a su propio código.

Mira la muestra de nuevo:

var gen = generator(); console.log(''generated generator''); console.log(gen.next().value); // mock long long processing setTimeout(function() { console.log(gen.next().value); console.log(''Execute after timer fire''); }, 1000); console.log(''Execute after timer set''); /* result: generated generator start 0 Execute after timer set 1 Execute after timer fire */

¿Ver? La función del generador en sí no maneja la devolución de llamada. El código exterior lo hace.

La base está aquí. Puede elaborar este código para admitir la asincronía completa mientras mantiene la función del generador como una sincronización.

Por ejemplo, supongamos que geturl es una llamada asíncrona que devuelve un objeto de promise . puede escribir var html = yield getUrl(''www..com''); Esto salta fuera de tu código. Y el código externo hará cosas como:

var ret = gen.next(); ret.then(function (fetchedHTML) { // jumps back to your generator function // and assign fetchHTML to html in your code gen.next(fetchedHTML); });

Para una guía más completa, refiérase a this . Y repositorio como co , galaxy , suspend y etc.