ทำซ้ำคีย์อ็อบเจ็กต์ใน node.js


139

ตั้งแต่ Javascript 1.7 มีวัตถุIteratorซึ่งอนุญาตสิ่งนี้:

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

มีอะไรแบบนี้ใน node.js?

ตอนนี้ฉันกำลังใช้:

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

แต่นั่นทำให้เกิดค่าใช้จ่ายจำนวนมากโดยการเก็บคีย์วัตถุทั้งหมดkไว้


คุณเคยเห็นสิ่งนี้ไหม ejohn.org/blog/unimpressed-by-nodeiterator
jcolebrand

2
ค่าใช้จ่ายอะไร คุณมีปุ่มและตัววนซ้ำกี่ตัว หากผลิตภัณฑ์ของพวกเขาน้อยกว่า 1 ล้านคนให้เพิกเฉยต่อ 'ไร้ประสิทธิภาพ' นี้
c69

@ jcolebrand φ: ดูเหมือนว่าcreateNodeIteratorสำหรับองค์ประกอบ DOM ฉันไม่ได้มี DOM;) @ c69: ฉันเก็บข้อมูลทั้งหมดในkeysวัตถุและvalueตั้งค่าเป็นเพียง1(ประมาณ 20MB ใน 700k ปุ่ม) แน่นอนสำหรับ ตอนนี้ฉันแค่ไม่สนใจนี้ 'ค่าใช้จ่าย' แต่ฉันต้องการที่ดีกว่าการแก้ปัญหา :)
stewe

ฉันเห็นว่าเป็นชั้นเรียนที่จะยุ่งกับ ;-)
jcolebrand

คำตอบ:


246

สิ่งที่คุณต้องการคือการทำซ้ำอย่างเกียจคร้านเหนือวัตถุหรืออาร์เรย์ สิ่งนี้เป็นไปไม่ได้ใน ES5 (ซึ่งไม่สามารถทำได้ใน node.js) เราจะได้สิ่งนี้ในที่สุด

ทางออกเดียวคือการหาโหนดโมดูลที่ขยาย V8 เพื่อดำเนินการตัวทำซ้ำ (และอาจกำเนิด) ฉันไม่พบการใช้งานใด ๆ คุณสามารถดูซอร์สโค้ด spidermonkey และลองเขียนใน C ++ เป็นส่วนขยาย V8

คุณสามารถลองต่อไปนี้ได้ แต่มันจะโหลดกุญแจทั้งหมดลงในหน่วยความจำด้วย

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

อย่างไรก็ตามเนื่องจากObject.keysเป็นวิธีการเนทีฟ

เกณฑ์มาตรฐาน

อย่างที่คุณเห็น Object.keys นั้นเร็วกว่ามาก การจัดเก็บหน่วยความจำจริงจะเหมาะสมที่สุดหรือไม่นั้นแตกต่างกัน

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

ขอบคุณนี้ช่วยเพิ่ม iterator ฉันบิต :) (การปรับปรุงรหัส) แต่เศร้าหน่วยความจำยังคงปัญหา :( และผมก็ไม่สามารถใช้forEachเพราะแต่ละขั้นตอนย้ำควรจะเรียกจาก async setTimeout.
stewe

@stewe เพิ่ม anasync.forEach
Raynos

ขอบคุณสำหรับการชี้แจง! ฉันอาจจะลองใช้วิธีการขยาย c ++
ตุ๋น

2
@stewe ถ้าคุณจัดการที่จะเขียนเผยแพร่บน github และทิ้งลิงค์ไปที่คำตอบที่นี่หรือความคิดเห็น o /
Raynos

@stewe เกี่ยวกับส่วนขยาย C ++ นั้นคุณเขียนมันหรือไม่?
Raynos

22

โปรดจำไว้ว่าคุณสามารถส่งผ่านอาร์กิวเมนต์ที่สองไปยัง.forEach()ฟังก์ชันที่ระบุวัตถุที่จะใช้เป็นthisคำหลัก

// 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
ส่วนเพิ่มเติมที่ดีของเธรด แต่ ... ทำไมบนโลกจึงแสดงคีย์ของวัตถุที่ถูกส่งผ่านเป็นสิ่งที่เรียกว่า "องค์ประกอบ" และตัวแจงนับสำหรับอาร์เรย์คีย์ที่เรียกว่า "คีย์"! ฉันขอแนะนำให้คุณอัปเดตตัวอย่างโค้ดของคุณเพื่อใช้งานได้Object.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz

4

สำหรับการทำซ้ำคีย์ / ค่าอย่างง่ายบางครั้งไลบรารีเช่นunderscorejsอาจเป็นเพื่อนของคุณได้

const _ = require('underscore');

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

เพียงเพื่อการอ้างอิง


มันใช้งานได้สำหรับฉัน ไม่รู้เรื่องunderscorejsเลย ฉันใช้ฟังก์ชั่นนี้จากlodashไลบรารี
Neerali Acharya

3

ฉันใหม่กับ node.js (ประมาณ 2 สัปดาห์) แต่ฉันเพิ่งสร้างโมดูลที่รายงานซ้ำไปยังคอนโซลเนื้อหาของวัตถุ มันจะแสดงรายการทั้งหมดหรือค้นหารายการที่ต้องการจากนั้นเจาะลึกตามความต้องการที่ระบุ

บางทีคุณสามารถปรับแต่งสิ่งนี้ให้เหมาะกับความต้องการของคุณ ง่าย ๆ เข้าไว้! ทำไมต้องซับซ้อน ...

'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

ปรับรหัสของเขา:

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);
    });
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.