Itérer sur les clés d'objet dans node.js


139

Depuis Javascript 1.7, il existe un objet Iterator , qui permet ceci:

var a={a:1,b:2,c:3};
var it=Iterator(a);

function iterate(){
    try {  
        console.log(it.next());
        setTimeout(iterate,1000);
    }catch (err if err instanceof StopIteration) {  
        console.log("End of record.\n");  
    } catch (err) {  
        console.log("Unknown error: " + err.description + "\n");  
    }  

}
iterate();

y a-t-il quelque chose comme ça dans node.js?

En ce moment, j'utilise:

function Iterator(o){
    /*var k=[];
    for(var i in o){
        k.push(i);
    }*/
    var k=Object.keys(o);
    return {
        next:function(){
            return k.shift();
        }
    };
}

mais cela produit beaucoup de surcharge en stockant toutes les clés d'objet dans k.



2
Quels frais généraux? Combien de clés et d'itérateurs avez-vous? Si leur produit est inférieur à 1 million, ignorez simplement cette «inefficacité».
c69

@jcolebrand φ: Il semble que ce createNodeIteratorsoit pour les éléments DOM, je n'ai même pas de DOM;) @ c69: je stocke toutes les données dans le keysde l'objet et le valueest juste réglé sur 1(environ 20 Mo dans 700k clés), en effet, pour maintenant, j'ignore simplement cette «surcharge», mais je préférerais une meilleure solution :)
stewe

Je l'ai vu comme une classe à jouer ;-)
jcolebrand

Réponses:


246

Ce que vous voulez, c'est une itération paresseuse sur un objet ou un tableau. Ce n'est pas possible dans ES5 (donc pas possible dans node.js). Nous finirons par y arriver.

La seule solution est de trouver un module de nœud qui étend V8 pour implémenter des itérateurs (et probablement des générateurs). Je n'ai trouvé aucune implémentation. Vous pouvez consulter le code source de spidermonkey et essayer de l'écrire en C ++ en tant qu'extension V8.

Vous pouvez essayer ce qui suit, mais cela chargera également toutes les clés en mémoire

Object.keys(o).forEach(function(key) {
  var val = o[key];
  logic();
});

Cependant, comme il Object.keyss'agit d'une méthode native, cela peut permettre une meilleure optimisation.

Référence

Comme vous pouvez le voir, Object.keys est nettement plus rapide. Que le stockage réel de la mémoire soit plus optimal est une autre question.

var async = {};
async.forEach = function(o, cb) {
  var counter = 0,
    keys = Object.keys(o),
    len = keys.length;
  var next = function() {
    if (counter < len) cb(o[keys[counter++]], next);
  };
  next();
};

async.forEach(obj, function(val, next) {
  // do things
  setTimeout(next, 100);
});

! Merci, ce qui améliore mon iterator un peu :) (mis à jour le code) , mais malheureusement , les restes d'émission de mémoire :( Et je ne peux pas utiliser forEachpuisque chaque étape d'itération doit être invoquée à partir d' un async setTimeout.
Stewe

@stewe a ajouté unasync.forEach
Raynos

Merci pour la clarification! J'essaierai probablement l'approche d'extension c ++.
stewe le

2
@stewe si vous parvenez à l'écrire, publiez-le sur github et laissez un lien vers celui-ci dans une réponse ici ou un commentaire o /
Raynos

@stewe à propos de cette extension C ++, l'avez-vous créée?
Raynos

22

N'oubliez pas également que vous pouvez passer un deuxième argument à la .forEach()fonction en spécifiant l'objet à utiliser comme thismot - clé.

// myOjbect is the object you want to iterate.
// Notice the second argument (secondArg) we passed to .forEach.
Object.keys(myObject).forEach(function(element, key, _array) {
  // element is the name of the key.
  // key is just a numerical value for the array
  // _array is the array of all the keys

  // this keyword = secondArg
  this.foo;
  this.bar();
}, secondArg);

5
bel ajout au fil, mais ... pourquoi diable montrer la clé de l'objet passé comme quelque chose appelé "élément", et l'énumérateur pour le tableau de clés appelé "clé"?! Puis-je vous suggérer de mettre à jour votre exemple de code à utiliserObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz

4

Pour une itération simple des clés / valeurs, des bibliothèques comme les underscorejs peuvent parfois être votre ami.

const _ = require('underscore');

_.each(a, function (value, key) {
    // handle
});

Juste pour référence


Cela a fonctionné pour moi. Je ne sais pas underscorejs. J'ai utilisé cette fonction de la lodashbibliothèque.
Neerali Acharya

3

Je suis nouveau sur node.js (environ 2 semaines), mais je viens de créer un module qui rapporte de manière récursive à la console le contenu d'un objet. Il listera tout ou recherchera un élément spécifique, puis explorera d'une profondeur donnée si nécessaire.

Vous pouvez peut-être le personnaliser en fonction de vos besoins. Rester simple! Pourquoi compliquer? ...

'use strict';

//console.log("START: AFutils");

// Recusive console output report of an Object
// Use this as AFutils.reportObject(req, "", 1, 3); // To list all items in req object by 3 levels
// Use this as AFutils.reportObject(req, "headers", 1, 10); // To find "headers" item and then list by 10 levels
// yes, I'm OLD School!  I like to see the scope start AND end!!!  :-P
exports.reportObject = function(obj, key, level, deep) 
{
    if (!obj)
    { 
        return;
    }

    var nextLevel = level + 1;

    var keys, typer, prop;
    if(key != "")
    {   // requested field
        keys = key.split(']').join('').split('[');
    }
    else
    {   // do for all
        keys = Object.keys(obj);
    }
    var len = keys.length;
    var add = "";
    for(var j = 1; j < level; j++)
    {
        // I would normally do {add = add.substr(0, level)} of a precreated multi-tab [add] string here, but Sublime keeps replacing with spaces, even with the ["translate_tabs_to_spaces": false] setting!!! (angry)
        add += "\t";
    }

    for (var i = 0; i < len; i++) 
    {
        prop = obj[keys[i]];
        if(!prop)
        {
            // Don't show / waste of space in console window...
            //console.log(add + level + ": UNDEFINED [" + keys[i] + "]");
        }
        else
        {
            typer = typeof(prop);
            if(typer == "function")
            {
                // Don't bother showing fundtion code...
                console.log(add + level + ": [" + keys[i] + "] = {" + typer + "}");
            }
            else
            if(typer == "object")
            {
                console.log(add + level + ": [" + keys[i] + "] = {" + typer + "}");
                if(nextLevel <= deep)
                {
                    // drop the key search mechanism if first level item has been found...
                    this.reportObject(prop, "", nextLevel, deep); // Recurse into
                }
            }
            else
            {
                // Basic report
                console.log(add + level + ": [" + keys[i] + "] = {" + typer + "} = " + prop + ".");
            }
        }
    }
    return ;
};

//console.log("END: AFutils");

0

ajuster son code:

Object.prototype.each = function(iterateFunc) {
        var counter = 0,
keys = Object.keys(this),
currentKey,
len = keys.length;
        var that = this;
        var next = function() {

            if (counter < len) {
                currentKey = keys[counter++];
                iterateFunc(currentKey, that[currentKey]);

                next();
            } else {
                that = counter = keys = currentKey = len = next = undefined;
            }
        };
        next();
    };

    ({ property1: 'sdsfs', property2: 'chat' }).each(function(key, val) {
        // do things
        console.log(key);
    });
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.