2010-11-08 24 views
47

Y at-il un moyen d'obtenir generators dans node.js?Est-ce que node.js supporte yield?

Je suis actuellement imitez avec callbacks, mais je dois vous rappeler de vérifier la réponse du rappel à l'intérieur de ma fonction de générateur qui crée beaucoup de if (callback(arg) === false) return;

Je veux quelque chose comme en python:

for p in primes(): 
    if p > 100: break 
    do_something(p) 

que je fais dans le nœud comme ceci:

primes(function(p) { 
    if (p > 100) return false; 
    do_something(p) 
}); 

peut-être quelque chose comme coffeescript pourrait aider?

+0

Coffeescript ne recevra probablement pas de générateurs de sitôt: https://github.com/jashkenas/coffee-script/issues/issue/983#issue/983/comment/639738 – Amir

+1

Notez aussi que JavaScript utilise camelCase pour les fonctions, ie 'doSomething', pas' do_something' – mikemaccana

Répondre

23
+4

mais leur version actuelle est 'v0.10.24', je suis confus. – Michelle

+2

La dernière version stable est v.0.10.24, mais vous pouvez toujours obtenir une version instable [ici] (http://nodejs.org/dist/) (actuellement v0.11.10). Les versions sont toujours annoncées dans le nœud [blog] (http://blog.nodejs.org/release/) (avec changelog). Les documents v0.11.10 sont [ici] (http://nodejs.org/dist/v0.11.10/docs/api/). Cela n'aurait pas dû être difficile à trouver, à partir de la [page d'accueil Nodejs.org] (http://nodejs.org)> [Téléchargements] (http://nodejs.org/download/)> [Autres versions] (http://nodejs.org/dist/). –

+0

Je n'arrive pas à les faire fonctionner, même avec le drapeau '--harmony' dans le noeud v0.10.29. – mpen

0

Mise à jour 2014: le nœud prend en charge les rappels maintenant. Ce qui suit est un article de 2010.


Vous devez utiliser des rappels. Si la fonction fait quelque chose de façon asynchrone, vous pouvez également un rappel de continuation (suite est un mauvais mot, car cela signifie aussi quelque chose d'autre, mais vous obtenez mon point.)

primes(function(p) { 
    if (p > 100) return false // i assume this stops the yielding 
    do_something(p) 
    return true // it's also better to be consistent 
}, function(err) { // fire when the yield callback returns false 
    if (err) throw err // error from whatever asynch thing you did 
    // continue... 
}) 

Mis à jour par exemple le code

Je l'ai retourné, de sorte qu'il renvoie true à la fin (puisque null, false et undefined tous évaluent à false de toute façon).

function primes(callback) { 
    var n = 1, a = true; 
    search: while (a) { 
    n += 1; 
    for (var i = 2; i <= Math.sqrt(n); i += 1) 
     if (n % i == 0) 
     continue search; 
    if (callback(n)) return 
    } 
} 

primes(function(p) { 
    console.log(p) 
    if (p > 100) return true 
}) 
+0

Mais alors ma fonction 'primes' est jonchée de' if (callback (arg) === false) return; ' au lieu de simplement 'arg' rendement. Est-ce censé être si moche? –

+1

'do {/ * configuration des données de rappel * /} while (callback (arg)); suite() '? Rappelez-vous que ce n'est pas aussi important à l'intérieur de la fonction, tant que l'interface et la sortie sont bonnes. –

+0

oh, et en ce qui concerne votre fonction prime (je suppose que vous faites une imbrication compliquée), vous devrez le coder de manière à pouvoir tout lâcher, passer en callback, puis recommencer à l'itération suivante (en utilisant des variables temporaires pour conserver l'état), ou vous devrez juste vivre avec les multiples lignes de rappel. –

2

Oui et non. Comme vous le voyez, vous pouvez implémenter quelque chose comme un utilisant des fermetures, mais il n'a pas de générateurs natifs.

2

Le issue proposant des générateurs dans la version 8 a récemment été accepté par le membre du projet v8.
S'il vous plaît voter là pour faire yield devenir réalité.

4

Vous pouvez utiliser des générateurs dans Node.js, mais seulement dans 0.11+. Node.js 0.12 (stable) est maintenant disponible. Ajoutez --harmony_generators ou --harmony aux paramètres de ligne de commande du noeud pour l'activer.

Avec Traceur, vous pouvez compiler du code JavaScript avancé en JavaScript. Vous pourriez faire un chargeur pour le noeud.js qui fait ça à la volée. Comme il s'exécute, et compile en JavaScript à la vanille, il s'exécute dans node.js < 0.11 ainsi que dans le navigateur.

Facebook a développé une version plus légère qui ne supporte que les générateurs, appelée Regenerator. Cela fonctionne de la même manière que Traceur.

3

Apparemment pas dans la version stable actuelle. Vous pouvez cependant réaliser la même chose en utilisant node-fibres + promesses.

Voici mon implémentation:

var fiber = require('fibers'); 

module.exports.yield = function (promise) { 

    var currentFiber = fiber.current; 
    promise 
     .then(function (value) { 
      currentFiber.run(value); 
     }) 
     .otherwise(function (reason) { 
      currentFiber.throwInto(reason); 
     }); 

    return fiber.yield(); 
}; 
module.exports.spawn = function (makeGenerator) { 
    fiber(function() { 
     makeGenerator.apply(this, Array.prototype.slice.call(arguments, 1)); 
    }).run(); 
}; 

Et un exemple de code sur la façon dont cela fonctionne: (query.find retourne une promesse)

 var generators = require('./utils/generators'); 
     var query = require('./utils/query'); 

     generators.spawn(function() { 
      try { 
       var field1 = generators.yield(query.find('user', { _id : '1' })); 
       var field2 = generators.yield(query.find('user', { _id : '2' })); 
       console.log('success', field1[0]._id, field2[0]._id); 
      } 
      catch (e) { 
       console.error('error', e); 
      } 
     }); 
+0

pourriez-vous s'il vous plaît également poster le code source pour la requête? cela fonctionnera-t-il avec n'importe quel système de rappel? – kroe