Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Node.js - Recursive Walker (https://javascript.ru/forum/project/28773-node-js-recursive-walker.html)

DreamTheater 02.06.2012 01:51

Node.js - Recursive Walker
 
Что делает:
Рекурсивно проходит от указанного корня и эмитирует события о всех найденных файлах и директориях.

Исходный код:
// Walker.js

var EventEmitter = require('events').EventEmitter,

    fs = require('fs'),
    path = require('path'),
    util = require('util');

module.exports = (function () {
    function Walker() {
        EventEmitter.call(this);
    }

    util.inherits(Walker, EventEmitter);

    Walker.prototype.walk = function (from) {
        try {
            var root = path.resolve(from),
                tree = fs.readdirSync(root);

            this.emit('directory', root);

            tree.forEach(function (leaf) {
                var branch = path.join(root, leaf),
                    stats = fs.statSync(branch);

                if (stats.isFile()) {
                    this.emit('file', branch);
                } else {
                    this.walk(branch);
                }
            }, this);
        } catch (error) {
            this.emit('error', error);
        }

        return this;
    };

    return Walker;
}());


Как использовать:
// sandbox.js

var Walker = require('./Walker');

(function () {
    var walker = new Walker();

    walker.on('file', function (file) {
        console.log('file:', file);
    });

    walker.on('directory', function (directory) {
        console.log('directory:', directory);
    });

    walker.on('error', function (error) {
        console.log('error:', error);
    });

    walker.walk('C:\Windows');
}());


Что получится:
Код:

directory: C:\Windows
directory: C:\Windows\AppCompat
error: { [Error: EPERM, operation not permitted 'C:\Windows\AppCompat\Programs']
  errno: 50,
  code: 'EPERM',
  path: 'C:\\Windows\\AppCompat\\Programs',
  syscall: 'readdir' }
directory: C:\Windows\AppPatch
file: C:\Windows\AppPatch\AcGenral.dll
file: C:\Windows\AppPatch\AcLayers.dll
...

Работает полностью синхронно, то есть никаких заморочек с коллбэками.

Прошу кидать помидорами.

Gvozd 02.06.2012 02:56

Цитата:

Сообщение от DreamTheater
Работает полностью синхронно, то есть никаких заморочек с коллбэками.

Цитата:

Сообщение от DreamTheater
Node.js

Не замечаете явной нестыковки?
По-моему должно быть очевидно, что любая библиотека для Node.Js должна быть обязательно ассинхронной(там где нужно и возможно, разумеется), и лишь только во вторую очередь, в ней возможно может быть синхронный вариант для всех ее асинхронных функций.
Или я чего-то не понимаю в Node.js?

Gvozd 02.06.2012 02:58

Цитата:

Сообщение от DreamTheater
то есть никаких заморочек с коллбэками.

я увидел в вашем примере "Как использовать:" целых три колбека
Что я делаю не так?

DreamTheater 02.06.2012 03:19

Gvozd, Вы безусловно правы. Я не имею богатого опыта написания приложений на Node.js, поэтому могу не знать кое-каких аспектов. Я читал что основная фишка Node.js это именно асинхронность, но она же и становится камнем преткновения во многих задачах, когда "коллбэк на коллбэке и коллбэком погоняет". Даже на одной конференции, еще когда на уровне ядра Node.js не было синхронной реализации многих методов, один из докладчиков "жаловался" на это обстоятельство.

Что до моих трех коллбэков, то это скорее слушатели. Я же имел ввиду что не стоит придумывать некий велосипед чтобы словить нужный момент времени.

Gvozd 02.06.2012 04:12

Цитата:

Сообщение от DreamTheater
но она же и становится камнем преткновения во многих задачах, когда "коллбэк на коллбэке и коллбэком погоняет"

я где-то слышал фразу о том, что многопоточность во всей ее красе и полноте(с разделением общих ресурсов, и разрешением гонок) хорошо понимают лишь 5% разработчиков.
с асинхронностью похожая ситуация, ИМХО.

Но, мне кажется более правильным будет все-таки реализация библиотеки в рамках реалий языка(то есть асинхронной), чтобы с ее помощью можно было написать хорошее приложение, и лишь только после этого можно добавить синхронный режим, чтобы его можно было использовать в тех задачах, где допустима синхронность на этой операции, и в тех проектах, где разработчики не могут мыслить асинхронно.

DreamTheater 02.06.2012 04:16

Цитата:

Сообщение от Gvozd (Сообщение 178172)
Но, мне кажется более правильным будет все-таки реализация библиотеки в рамках реалий языка(то есть асинхронной), чтобы с ее помощью можно было написать хорошее приложение, и лишь только после этого можно добавить синхронный режим, чтобы его можно было использовать в тех задачах, где допустима синхронность на этой операции, и в тех проектах, где разработчики не могут мыслить асинхронно.

Ну, именно для таких комментариев я и создал данный топик. В дискуссиях рождается истина :)

DreamTheater 02.06.2012 19:11

Только что написал асинхронный аналог. Время полной отработки внутри каталога C:\Windows ~22 секунды. То же самое но с синхронной реализацией выше - ~1,5 секунды.

Целесообразность использовать асинхронность для меня под сильным вопросом.

Gvozd 02.06.2012 19:22

Цитата:

Сообщение от DreamTheater
синхронной реализацией выше - 1,5 секунды.

В эти 1.5 секунды не будет выполнятся никакой другой запрос
Цитата:

Сообщение от DreamTheater
~22 секунды.

За эти 22 секунды параллельно могут быть обработаы сотни-тысячи других запросов

DreamTheater 02.06.2012 19:39

Цитата:

Сообщение от Gvozd (Сообщение 178294)
В эти 1.5 секунды не будет выполнятся никакой другой запрос

За эти 22 секунды параллельно могут быть обработаы сотни-тысячи других запросов

В случае веб-сервера да, но в случае консольной тулзы это не нужно.

Gvozd 02.06.2012 19:57

Цитата:

Сообщение от DreamTheater
В случае веб-сервера да, но в случае консольной тулзы это не нужно.

Node.js это все-таки в первую очередь веб-сервер же.
И поэтому в первую очередь должен быть асинхронный вариант, и лишь потом для таких применений как консольная утилита, можно сделать синхронный вариант.
Раз вы реализовали и синхронный и асинхронные варианты, то можно распространять библиотеку с обоими вариантами же, и любой, кому нужна такая библиотека будет доволен тем, что нашел нужный вариант

DreamTheater 02.06.2012 20:02

На самом деле уже есть похожее решение. Просто мне захотелось попробовать самому :)

B~Vladi 04.06.2012 21:13

Цитата:

Сообщение от Gvozd
По-моему должно быть очевидно, что любая библиотека для Node.Js должна быть обязательно ассинхронной(там где нужно и возможно, разумеется), и лишь только во вторую очередь, в ней возможно может быть синхронный вариант для всех ее асинхронных функций.

Странное утверждение. Если говорить про либу от ТС - да, здесь в первую очередь должен быть асинхронный вариант. Асинхронность нужна там, где нода обращается к внешним ресурсам (база, файловая система), включая всякие обертки вокруг этого (как Recursive Walker), и при чистых тяжелых вычислениях (числа фибоначчи).
Если вычисления выполняются до 3-5 мс: добавлять асинхронность нет смысла.

Gvozd 04.06.2012 21:45

Оговорка в скобках написана невидимыми буквами?

B~Vladi 04.06.2012 21:52

Ога ^^

Kolyaj 05.06.2012 10:45

Цитата:

Сообщение от DreamTheater
Только что написал асинхронный аналог. Время полной отработки внутри каталога C:\Windows ~22 секунды.

Исходники покажите.

DreamTheater 05.06.2012 12:07

Цитата:

Сообщение от Kolyaj (Сообщение 179066)
Исходники покажите.

var EventEmitter = require('events').EventEmitter,

    fs = require('fs'),
    path = require('path'),
    util = require('util');

module.exports = (function () {
    function Walker() {
        EventEmitter.call(this);
    }

    util.inherits(Walker, EventEmitter);

    Walker.prototype.walk = function (from) {
        var root = path.resolve(from),

            callback = function (error, tree) {
                if (error !== null) {
                    return this.emit('error', error);
                }

                tree.forEach(function (leaf) {
                    var branch = path.join(root, leaf),

                        callback = function (error, stats) {
                            if (error !== null) {
                                return this.emit('error', error);
                            }

                            if (stats.isFile()) {
                                this.emit('file', branch);
                            } else if (stats.isDirectory()) {
                                this.walk(branch);
                            }
                        }.bind(this);

                    fs.stat(branch, callback);
                }, this);
            }.bind(this);

        this.emit('directory', root);

        fs.readdir(root, callback);

        return this;
    };

    return Walker;
}());

Kolyaj 05.06.2012 12:10

А как вы время выполнения вычислили, если у вас окончание перебора нигде не фиксируется?

DreamTheater 05.06.2012 12:32

Так, на часах засек :D

Kolyaj 05.06.2012 12:42

Сделайте для тренировки событие end. Код значительно усложнится.

DreamTheater 05.06.2012 12:43

Цитата:

Сообщение от Kolyaj (Сообщение 179100)
Сделайте для тренировки событие end. Код значительно усложнится.

Да-да, именно поэтому я пока его не выкладываю. Хочу сделать более красиво все.

DreamTheater 06.06.2012 10:56

Цитата:

Сообщение от DreamTheater (Сообщение 178288)
Только что написал асинхронный аналог. Время полной отработки внутри каталога C:\Windows ~22 секунды. То же самое но с синхронной реализацией выше - ~1,5 секунды.

Поправочка: в синхронном варианте время выполнения примерно такое же. Синхронный скрипт останавливается пройдя 4 тыс. файлов, в то время как в действительности их в каталоге около 60 тыс. Асинхронный же крутит до конца.

B~Vladi 16.06.2012 16:03

Цитата:

Сообщение от DreamTheater
EventEmitter.call(this);

В какой версии это работает? У меня в 0.6.18-19 не работает.

DreamTheater 16.06.2012 16:07

0.6.18 у меня. Взято из родной доки http://nodejs.org/docs/latest/api/ut...rcons tructor

B~Vladi 16.06.2012 16:21

Странно что у тебя работает. В исходниках это пустая функция:
function EventEmitter() { }

Методы добавляются в прототип.

B~Vladi 16.06.2012 16:23

А, пропустил это:
util.inherits(MyStream, events.EventEmitter);

DreamTheater 06.07.2012 14:19

Фича неактуальна, нашел вот такую штуку :)


Часовой пояс GMT +3, время: 11:29.