All streams
Search
Write a publication
Pull to refresh
4
0

User

Send message
Отличная статья!
Идея (по крайней мере, для меня) новая, и, разумеется, имеет полное право на существование.

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

От себя хотел выделить правило: Никогда не используй название свойств объектов JS для хранения даннных. Свойства объектов используем только для структурирования данных.
Хранение данных в названиях свойств объектов равносильно хранению данных в названиях столбцов в таблицах реляционных СУБД.

Выше, в комментариях, обсуждалась технологическая проблема, в следствии которой приходилось держать отдельный массив для быстрого доступа к данным по сложному ключу или для сортировки этих данных. В теории СУБД такие массивы называются индексами. В использовании массивов такого назначения нет ничего плохого.
Если не нравится то, что приходится использовать несколько разных массивов с разными именами, один из самых производительных способов — создать свой класс, наследуемый от Array или Collection. Ну, и реализовать работу всех индексов в рамках этого класса.
Итак, скрин делать не буду. Оставлю результаты текстом.
Node v0.12.4

for(var i = 0, l = 1000 * 1000 * 1000; i < l; i++) { var obj = {} }                                 //  =>  0:07.29
for(var i = 0, l = 1000 * 1000 * 1000; i < l; i++) { var obj = new Object() }                       //  =>  0:34.58
for(var i = 0, l = 1000 * 1000 * 1000; i < l; i++) { var obj = Object.create(Object.prototype); }   //  =>  1:11.67
for(var i = 0, l = 1000 * 1000 * 1000; i < l; i++) { var obj = Object.create(null) }                //  =>  1:50.54
Да, Вы правы по поводу Object.create().
Поротестировал много разных вариантов прототипов.
Результаты приблизительно одинаковы везде — 4 минуты ± 15 секунд.
Тест показывал неоптимизированность именно Object.create().
Сами тесты проводил самыми стандартными средствами: readline-интерфейс node и top с фильтром результатов по pid.

Есть еще один хороший сервис тестирования, но через браузер: jsperf.com/naked-vs-simple-objects
Тут надо быть вимательным, результаты отличаются в разных браузерах на разных ОС.

Также, по заявкам трудящихся на комментарий ниже, к утру потестирую вышеперечисленное на node v0.12.4.
Что примечательно, запустил один и тот же код по созданию млрд обычных объектов и млрд голых. Память оба процесса расходуют одинаково. А вот процессорное время голые съели заметно больше, чем обычные.
Обычные объекты создались за 43 с хвостиком секунды процессорного времени.
Голые съели больше 4х минут.
Скриншот прилагается. Node v0.10.26
Даже возвращать новый класс необязательно, можно вкорячить прототип и в старый класс.

mixClass(Client, Security);

function mixClass(cl, mx) {
    var resClass = cl.prototype.constructor;
    util.inherits(resClass, mx);
    util.inherits(resClass, cl);
    cl.prototype = Object.create(resClass.prototype);
}
Заметил еще косяк, что потерял конструктор. Правильнее было бы так:

var SecurityClient = mixClass(Client, Security);

function mixClass(cl, mx) {
    var resClass = cl.prototype.constructor;
    util.inherits(resClass, mx);
    util.inherits(resClass, cl);
    return resClass;
}
По части curr вы правы. Для корректного понимания IDE можно добавить в комментарий @returns {function}. Ну, а как пользоваться сей конструкцией можно разъяснить в свободной форме в формате markdown в том же комментарии.

По поводу примисей и наследования я понял, что Вы хотели донести. Но все это можно реализовать и с util.inherits(). Разница лишь в том, что util.inherits(Client, Security) оставит методы и свойства Client, если таковые имеются в Security.

То есть, например, есть классы Security и Client. Если реализовать так, то методы и свойства Security будут поверх Client:

var SecurityClient = mixClass(Client, Security);

function mixClass(cl, mx) {
    var resClass = function(){};
    util.inherits(resClass, mx);
    util.inherits(resClass, cl);
    return resClass;
}


Как оформить сие добро в jsdoc не могу уверенно предложить. Но, могу с уверенностью сказать, может примиси и удобный для web инструмент (в браузере много стандартных классов, в которых можно расширять функционал: HTMLDocument, XMLHttpRequest), но в Node.JS я бы уверенно обходился бы без них, с базовым одноуровневым наследованием.

Так или иначе, все зависит от конкретной задачи.
Я не понимаю вашего негодования.

Я не против фабрик, но у каждого класса должно быть «жесткое» имя, закрепленное в своем namespace.
То есть, да, разумно к тому коду, что есть приделать возможность получения класса через фабрику. Это бы помогло в случае, например, если тип хранилища указан в конфиге. Но обязательно должна остаться возможность получить класс и по «жесткой» ссылке.

/**
 * @name storage.getStorage
 * @returns {storage.FsStorage|storage.MysqlStorage|storage.MongoStorage}
 */


Замыкания к процессу документирования вообще никакой гранью не могу отнести.

По поводу динамических примесей в прототипы. На Node.JS это реализованно util.inherits().
А в jsdoc множественное наследование можно описать:

/**
 * @name storage.MysqlStorage
 * @extends {storage.BaseStorage|storage.SqlStorage}
 * @constructor 
 */
Нет, как раз за это отвечает метки @constructor, @namespace и остальные.

Например, для обозначения namespace я добавлю в index.js:

/** @namespace storage */


А для класса, например:
/**
  * @name storage.FsStorage
  * @extends storage.BaseStorage 
  * @constructor 
  */


Классы я обычно определяю олдскул-способом Function().prototype.

Так, jsdoc шарится по всем файлам исходных кодов, а IDE тоже прекрасно понимает такие комментарии, структура кода всегда под рукой. Код готов к любому рефакторингу.
Кроме того, процессы node могут иметь такие состояния, когда их необходимо завершить или перезапустить:
  1. idle: процесс использует CPU на 0% продолжительное время. Тут может быть два варианта: если процесс выполнял какую-то работу, скорее всего процесс по какой-то причине потерял callback или что-то в этом роде. Такой процесс необходимо перезагрузить. Если данный процесс реализует, например, http-сервер с каким-нибудь малопосещаемым сайтом, то скорее всего такое состояние обусловленно тем, что на сайт никто давно не заходил. Такой процесс можно завершить, а при запросе на сайт, снова по быстрому поднять http-сервер.
  2. CPU-limit: процесс использует CPU на 100% (или свой ограниченный максимум) продолжительное время. Такой процесс скорее всего зациклился или попал на невыполнимый участок задачи. Такой процесс можно перезагрузить, чтобы сам не застревал на одной задаче и не мешал другим конкурирующим процессам.
  3. RAM-limit: процесс использует максимум выделенной для него памяти. Не секрет, что node-процессы по ходу своего выполнения текут. Совсем ожиревшие процессы тоже можно перезагружать. Это напоминает борьбу с утечками методом PHP. — То есть, зачем удалять ненужные переменные?! — все переменные удаляются вместе с завершением процесса.
По началу, я тоже использовал одновременное асинхронное выполнение кода в несколько потоков. Но, код выполняется в одном процессе, соответственно, на одном ядре CPU. Для использования максимума ресурсов обычно используется оба подхода: код работает в несколько процессов, каждый процесс из которых выполняет код в несколько потоков.

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

Так же мы используем общую документацию по всем проектам, пакетам, модулям. Для представления списка всех классов в древовидной форме, нам приходится лишь помогать jsdoc лишь указывая что есть @constructor, а что @namespace. Использование фабрик требовало бы модернизации сборщика/генератора документации.

Information

Rating
Does not participate
Registered
Activity