Iterate atas kunci objek di node.js

139

Karena Javascript 1.7 ada objek Iterator , yang memungkinkan ini:

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();

apakah ada sesuatu seperti ini di node.js?

Saat ini saya sedang menggunakan:

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

tapi itu menghasilkan banyak overhead dengan menyimpan semua kunci objek k.

pelayan
sumber
Pernahkah kamu melihat ini? ejohn.org/blog/unimpressed-by-nodeiterator
jcolebrand
2
Overhead apa? Berapa banyak kunci dan iterator yang Anda miliki? Jika produk mereka kurang dari 1 juta, abaikan saja 'inefisiensi' ini.
c69
@jcolebrand φ: Tampaknya createNodeIteratoruntuk elemen DOM, saya bahkan tidak punya DOM;) @ c69: saya menyimpan semua data di keysobjek dan valuehanya disetel ke 1(sekitar 20MB di tombol 700k), memang, untuk sekarang saya hanya mengabaikan 'overhead' ini, tetapi saya lebih suka solusi yang lebih baik :)
stewe
Saya melihatnya sebagai kelas yang harus dikacaukan ;-)
jcolebrand

Jawaban:

246

Yang Anda inginkan adalah iterasi malas atas objek atau array. Ini tidak mungkin di ES5 (jadi tidak mungkin di node.js). Kami akan mendapatkan ini pada akhirnya.

Satu-satunya solusi adalah menemukan modul simpul yang memperluas V8 untuk mengimplementasikan iterator (dan mungkin generator). Saya tidak dapat menemukan implementasi apa pun. Anda dapat melihat kode sumber spidermonkey dan mencoba menulisnya dalam C ++ sebagai ekstensi V8.

Anda dapat mencoba yang berikut ini, namun itu juga akan memuat semua kunci ke dalam memori

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

Namun karena Object.keysmerupakan metode asli, ini memungkinkan optimasi yang lebih baik.

Tolok ukur

Seperti yang Anda lihat, Object.keys secara signifikan lebih cepat. Apakah penyimpanan memori yang sebenarnya lebih optimal adalah masalah yang berbeda.

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);
});
Raynos
sumber
Terima kasih !, ini meningkatkan iterator saya sedikit :) (memperbarui kode) tetapi sayangnya masalah memori tetap :( Dan saya tidak dapat menggunakan forEachkarena setiap langkah iterasi harus dipanggil dari async setTimeout.
stewe
@stewe menambahkanasync.forEach
Raynos
Terimakasih atas klarifikasinya! Saya mungkin akan mencoba pendekatan ekstensi c ++.
stewe
2
@stewe jika Anda berhasil menulisnya, terbitkan di github dan tinggalkan tautan di sana sebagai jawaban di sini atau komentar o /
Raynos
@stewe tentang ekstensi C ++ itu, apakah Anda yang membuatnya?
Raynos
22

Ingat juga bahwa Anda dapat memberikan argumen kedua ke .forEach()fungsi yang menentukan objek untuk digunakan sebagai thiskata kunci.

// 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);
barista amatir
sumber
5
tambahan yang bagus untuk utas, tapi ... mengapa bumi menunjukkan kunci objek yang dilewatkan sebagai sesuatu yang disebut "elemen", dan enumerator untuk array kunci yang disebut "kunci"?! Dapatkah saya menyarankan Anda memperbarui sampel kode Anda untuk digunakanObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz
4

Untuk pengulangan sederhana nilai / kunci, terkadang pustaka seperti underscorejs bisa menjadi teman Anda.

const _ = require('underscore');

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

hanya untuk referensi

H6.
sumber
Ini berhasil untuk saya. Tidak tahu tentang underscorejs. Saya menggunakan fungsi ini dari lodashperpustakaan.
Neerali Acharya
3

Saya baru mengenal node.js (sekitar 2 minggu), tetapi saya baru saja membuat modul yang secara rekursif melaporkan ke konsol isi suatu objek. Ini akan mendaftar semua atau mencari item tertentu dan kemudian menelusuri kedalaman yang diberikan jika perlu.

Mungkin Anda dapat menyesuaikan ini sesuai dengan kebutuhan Anda. Tetap Sederhana! Kenapa menyulitkan? ...

'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");
Andrew Foster alias Sheff
sumber
0

sesuaikan kodenya:

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);
    });
Lindy
sumber