Lặp lại các khóa đối tượng trong node.js


139

Vì Javascript 1.7 có một đối tượng Iterator , cho phép điều này:

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

Có cái gì đó như thế này trong node.js?

Ngay bây giờ tôi đang sử dụng:

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

nhưng điều đó tạo ra rất nhiều chi phí bằng cách lưu trữ tất cả các khóa đối tượng k.


Bạn đã thấy cái này chưa? ejohn.org/blog/unimpressed-by-nodeiterator
jcolebrand

2
Chi phí gì? Bạn có bao nhiêu khóa và trình vòng lặp? Nếu sản phẩm của họ dưới 1 triệu, chỉ cần bỏ qua 'không hiệu quả' này.
c69

@jcolebrand: Có vẻ như createNodeIteratorlà đối với các phần tử DOM, tôi thậm chí không có DOM;) @ c69: Tôi lưu trữ tất cả dữ liệu trong keysđối tượng và thực tế valuechỉ được đặt thành 1(khoảng 20 MB trong 700k khóa), thực sự, cho bây giờ tôi chỉ bỏ qua 'chi phí' này, nhưng tôi thích một giải pháp tốt hơn :)
hầm

Tôi thấy nó là một lớp học bị rối tung ;-)
jcolebrand

Câu trả lời:


246

Những gì bạn muốn là lặp đi lặp lại lười biếng trên một đối tượng hoặc mảng. Điều này là không thể có trong ES5 (do đó không thể có trong node.js). Chúng tôi sẽ nhận được điều này cuối cùng.

Giải pháp duy nhất là tìm một mô-đun nút mở rộng V8 để thực hiện các trình vòng lặp (và có thể là các trình tạo). Tôi không thể tìm thấy bất kỳ thực hiện. Bạn có thể xem mã nguồn spidermonkey và thử viết nó bằng C ++ dưới dạng phần mở rộng V8.

Bạn có thể thử cách sau, tuy nhiên nó cũng sẽ tải tất cả các phím vào bộ nhớ

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

Tuy nhiên vì Object.keyslà một phương thức riêng nên nó có thể cho phép tối ưu hóa tốt hơn.

Điểm chuẩn

Như bạn có thể thấy Object.keys nhanh hơn đáng kể. Việc lưu trữ bộ nhớ thực tế là tối ưu hơn là một vấn đề khác.

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

! Xin cảm ơn, điều này cải thiện iterator của tôi một chút :) (cập nhật mã) nhưng đáng buồn là vấn đề cốt nhớ :( Và tôi không thể sử dụng forEachvì mỗi bước lặp nên được gọi từ một async setTimeout.
stewe

@stewe thêm mộtasync.forEach
Raynos

Cảm ơn bạn đã làm rõ! Tôi có thể sẽ thử cách tiếp cận mở rộng c ++.
hầm

2
@stewe nếu bạn quản lý để viết nó, xuất bản nó trên github và để lại một liên kết đến nó trong một câu trả lời ở đây hoặc một bình luận o /
Raynos

@stewe về phần mở rộng C ++ đó, ​​bạn có tác giả không?
Raynos

22

Cũng nhớ rằng bạn có thể truyền đối số thứ hai cho .forEach()hàm chỉ định đối tượng sẽ sử dụng làm thistừ khóa.

// 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
bổ sung tốt cho chủ đề, nhưng ... tại sao trên trái đất hiển thị khóa của đối tượng được truyền dưới dạng một cái gì đó gọi là "phần tử" và trình liệt kê cho mảng khóa gọi là "khóa"?! Tôi có thể đề nghị bạn cập nhật mẫu mã của mình để sử dụng khôngObject.keys(myObject).forEach(function(key, index, arrayOfKeys) {
Andy Lorenz

4

Để lặp lại khóa / giá trị đơn giản, đôi khi các thư viện như dấu gạch dưới có thể là bạn của bạn.

const _ = require('underscore');

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

Chỉ để tham khảo


Nó làm việc cho tôi. Đừng biết về underscorejs. Tôi đã sử dụng chức năng này từ lodashthư viện.
Neerali Acharya

3

Tôi mới sử dụng node.js (khoảng 2 tuần), nhưng tôi vừa tạo một mô-đun báo cáo đệ quy cho bảng điều khiển nội dung của một đối tượng. Nó sẽ liệt kê tất cả hoặc tìm kiếm một mục cụ thể và sau đó đi sâu vào một độ sâu nhất định nếu cần.

Có lẽ bạn có thể tùy chỉnh điều này để phù hợp với nhu cầu của bạn. Giữ cho nó đơn giản! Tại sao lại phức tạp? ...

'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

điều chỉnh mã của mình:

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);
    });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.