misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'tag', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

Поиск по метке: node

Подсчёт повторений слов в файле на коленке

18 января 2017

Примитивный скрипт на JavaScript, подсчитывающий кол-во повторений английских слов без учёта морфологии и пр. лингво-хитростей:

"use strict"; /* eslint-env es6 */

const fs = require('fs');

function calculate(source)
{
	const words = source
		.toLowerCase()
		.replace(/[^a-z0-9'’]+/gm, ' ')
		.split(/\s+/)
		.filter(s => s.length)
		.reduce((map, word) =>
		{
			if(!map.get(word))
				map.set(word, 0);
			map.set(word, map.get(word) + 1);
			return map;
		}, new Map());

	return Array.from(words)
		.sort((a, b) => a[1] < b[1] ? 1 : -1);
}

const [,, sourceF, destinationF ] = process.argv;
if(!fs.existsSync(sourceF))
	throw new Error('Couldn\'t find "' + sourceF + '" file');

const source = fs.readFileSync(sourceF).toString();
const words = calculate(source);
console.info('Found ' + words.length + ' words.');

const str = words
	.map(([word, count]) => `${word} = ${count}`)
	.join('\n');
fs.writeFileSync(destinationF, str);
console.info('Count-map\'s written into "' + destinationF + '" file');

Из простых, но действенных, решений можно фильтровать все слова:

  1. с апострофами (Mike's, I'm, You're, Can't, Don't, You'll, etc)
  2. отдельно стоящие числа (или вообще все слова с числами)

Если хочется больше заморочиться, то можно сподобиться и написать морфологическую "определялку" является ли слово множественной формой какого-то из других представленных слов. Но, по сути, чем глубже закопаешься, тем очевиднее будет, что для серьёзных задач стоит взять серьёзную лингво-либу.

Broadcast в PM2

4 апреля 2016

PM2 — это обёртка вокруг node-cluster для запуска nodeJS приложения, в виде нескольких instance's, каждый из которых представлен отдельным процессом. При этом, в стандартном применении, в качестве master-а выступает внутренний скрипт пакета pm2, а в качестве worker-ов ваше приложение. Они всё так же могут слушать один и тот же порт. PM2 (а может и не он) сам будет распределять запросы между worker-ами.

Рано или поздно может возникнуть необходимость коммуникации между worker-ами. Как её осуществить? Изначально worker-ы друг о друге ничего не знают, но если подключить require('pm2'), то через полученное API можно добиться многого. Нормальной документации к этому API, похоже не существует. Но большая часть доступных методов общая с CLI API.

Для начала необходимо подключиться к pm2 из worker-а:

const pm2 = require('pm2');
pm.conect(err =>
  {
    // с этого момента можно использовать API
  });

Для получения всех запущенных pm2-процессов (кроме master-а) можно воспользоваться pm2.list(). Он вернёт вам ВСЕ запущенные им процессы, включая те, что никак не связаны с вашим приложением. Включая текущий instance тоже. Возвращённая пачка данных изобилует подробностями. 3-10 KiB всякой ерунды на каждый worker.

Отфильтровать оттуда текущий instance можно сравнив pmID текущего процесса (process.env.pm_id), с pmID каждого worker-а из списка. Для того чтобы выфильтровать лишние процессы, не связанные с вашим приложением, можно воспользоваться name-ом (process.env.pm_id). Это значение name из json-pm2-профиля вашего приложения.

Метод list несколько избыточен, мягко говоря. Можно получить только pmID-ки worker-ов по указанному name-у. Для этого есть pm2.getProcessIdByName(name). Останется только выфильтровать из него pmID текущего процесса.

А для того, чтобы разослать каждому из worker-ов сообщение с данными, есть метод pm2.sendDataToProcessId(id, packet). Где packet должен быть объектом с ключами: topic (строка с ключом сообщения) и data (сами данные).

Получать сообщения можно как штатными методами pm2, через launchBus (что у меня сделать не получилось), так и штатным process.on('message', cb) от nodejs.

В итоге простой broadcast можно организовать примерно так:

// при инициализации приложения
pm.connect(err => {});

// отправка сообщения
function broadcast(topic, data)
{
	pm.getProcessIdByName(process.env.name, (err, ids) =>
	{
		if(err) {}
		else ids
			.filter(i => i != process.env.pm_id)
			.forEach(id =>
			{
				pm2.sendDataToProcessId(id, { topic, data }, err => {});
			});
	});
}

// приём
process.on('message', msg => { /* msg */ });

Ложка дёгтя

На getProcessIdByName на моей машине уходит от 6ms до 15ms. Т.е. очень очень много. Код внутри по любому поводу формирует и гоняет между процессами груду данных. Используются теже механизмы, что и задействуются для pm2 monit. Даже если запрашивался только ID

Почему нет никаких стандартных и удобных механизмом для коммуникации между процессами мне не ясно. Причём ни в pm2, ни в nodeJS. С nodeJS впринципе всё ясно, ведь использование node-cluster предполагает, что master всему голова и сам всё порешает. Но в случае pm2 ситуация несколько иная.

V8 & unicode RegExp-ы

21 марта 2016

Не так давно в V8 движок добавили поддержку флага /u (т.е. поддержку unicode) для регулярных выражений. В nodeJS можно подключить флагом --harmony_unicode_regexps. Вот небольшой обзор по новым возможностям. При установленном флаге . понимает иероглифы, их же стало можно использовать в описании регулярного выражения без экранирования, появилась поддержка i флага.

Но! Они недобавили самого вкусного ― \p{L}. При помощи модификатора \p можно кратко описать многие вещи (см. раздел Unicode Categories). К примеру можно описать в пару символом регулярку, которая будет проверять принадлежность символа к алфавиту какого-либо языка. Например, /^\p{L}[\p{L}\d-_ ]+$/u отлично подойдёт для валидации имени пользователя, не поставив в незавидное положение ни грузин, ни китайцев, ни русских. Но отлично отфильтрует рандомный бред с клавиатуры.

Надеюсь, что это временно. А пока можно воспользоваться, к примеру, XRegExp-ом.

V8 & Async Await

17 марта 2016

Очень жду от nodeJS поддержки async/await. А т.к. nodeJS использует V8, то, получается, я жду async/await именно от V8. Мне так и не удалось найти какого-либо публичного roadmap-а от команды, которая им занимается. Что мы имеем на данный момент?

Ну для начала у нас есть страница на официальном сайте nodeJS, посвящённая ES2015. Она бегло сообщает нам о том, что можно использовать готовые возможности из ES2015 под флагом --es_staging, и посмотреть список всех доступных по --v8-options. Также можно отфильтровать все v8 флаги по in-progress. К примеру мы уже можем использовать --harmony_default_parameters и --harmony_destructuring на свой страх и риск. Я использую, работает. Там же ошибочно указано, что можно включить --harmony_modules, но эту опцию просто забыли убрать.

Затем у нас есть issue в баг-трекере v8 c несколькими сообщениями. Выясняется, что пару лет назад, кто-то уже запиливал поддержку async/await в v8, но получилось не очень. А пока вроде прогресс даже не шевелится. Отсюда же ловим ссылку на то, как какой-то энтузиаст добавил поддержку синтаксиса async/await в виде патча, который отвергли со словами, мол, парень, для начала войти в v8-team.

We have some plans for tackling that next year, but not before we have finished ES6. To be honest, we would prefer not to open that can right now, since ES6 already is producing a lot of churn.

iefserge, 2015-10-27

Полную поддержку ES6 v8 пока не получил, хотя большая часть готова. Когда дойдут у команды руки до awanc/await неизвестно. Хорошо, если это произойдёт в 2016. Остаётся надеяться, что поддержка в Edge ускорит процесс появления оного и в v8.

UPD0: Нашёл RSS с новостями V8!

Javascrpt ES6 и классы

8 декабря 2015

Понемногу перебираюсь на JavaScript ES6 синтаксис. По мере появления его нативной поддержки в nodeJS и Chrome. ES6 таит в себе множество не очевидных вещей. Больше всего я их встретил в class-ах. Классы в ES6 это обширный набор синтаксического сахара для prototype. С ними писать код приятнее, да и сам синтаксис вынуждает подходить к этому дисциплинированнее. В этой мини-заметке я опишу пары интересных моментов:

  • Синтаксис допускает только короткие имена методов;
  • Тело класса описывает методы, которые будут помещены в prototype и статические методы, которые будут помещены в сам объект класса. Так вот… Таким образом вы можете поступить только с методами и generator-ми. Т.е. никаких хешей, никаких чисел, строк, регулярных выражений. Всё, что вы захотите поместить сверх методов и генераторов будет идти уже отдельными строками кода после описания класса;
  • Это ограничение довольно понятно. Дескать дисциплинирует все подобные вещи определять в конструкторе и не позволяет переписывать детьми в прототипе. Но… Почему то nodejs не поддерживает статические generator-ы. Не статические поддерживает, а на статические лови syntax error. Наверное это баг (static * name());
  • Для удобного доступа к родительским методам (имею ввиду наследование классов) придуман super. Но… Если вы переопределяете конструктор класса, вы:
    1. Обязаны вызвать super, чтобы получить доступ к this
    2. Да да. До этого момента this отсутствует как таковой. Соответственно вызвать родительский конструктор, предварительно задав какие-нибудь поля новому объекту, без бунов не получится. Зачем они так сделали? о_О.
  • Методы и генераторы заданные в теле класса будут не-enumerable. Но для получения их списка можно воспользоваться: Object.getOwnPropertyNames(Object.getPrototypeOf(this)).

Пока что это все грабли на которые я наткнулся. В скором времени ожидается поддержка со стороны Firefox.