uk
Feedback
HowProgrammingWorks - JavaScript and Node.js Programming

HowProgrammingWorks - JavaScript and Node.js Programming

Відкрити в Telegram

Программная инжененрия для JavaScript, TypeScrip, Node.js 👉 Group: https://t.me/How_Programming_Works 👉 Node.js channel: https://t.me/metarhia 👉 Node.js group: https://t.me/nodeua

Показати більше
6 542
Підписники
-124 години
-57 днів
+4430 день
Архів дописів
В Node.js для очередей используется FixedQueue на базе CircularBuffer. Он оптимизирован для V8, на базе списка массивов фиксированной длины по 2048 элементов. Это гораздо лучше, чем просто push/shift на массиве, когда массив постоянно меняет длину и память перераспределяется. Но все же очень неоптимально, потому, что нам для очереди нужно добавлять только в голову списка, а брать только с хвоста, не нужно по кругу бегать в буфере. Они неправильно выбрали структуру данных, тут не нужно было циркулярный буффер реализовывать, тут нужно использовать Unrolled List, эффективнее и проще. В текущей реализации, много лишнего кода, когнитивная нагрузка выше, там битовая маска используется, и вконце буфера один элемент всегда undefined, вот этот лишний undefined - как раз не страшно, но циркулярная машинерия медленнее. Тут есть 4 варианта кода, чтобы разобраться в вопросе: 1 - наивная очередь, 2 - очередь на списках, 3 - очередь на циркулярном буффере, 4 - очередь на развернутом списке. Для курса по паттернам я сделаю лекцию где мы подробне это разберем и составим сравнительную таблицу, для разных реализаций, где что оптимально использовать - https://github.com/HowProgrammingWorks/Queue/tree/main/JavaScript

Как изолировать стейт при помощи паттерна Actor и как написать Event loop при помощи Reactor и Proactor https://youtube.com/live/tpY01TLctAs

🧩 Завтра, 5 апреля, 15:00 — 18:00 будет стрим, на котором мы разберем патерны: Actor — Инкапсулирует состояние и поведение, взаимодействуя асинхронно через передачу и последовательную обработку сообщений в очереди. Обеспечивает потокобезопасность и асинхронную безопасность при параллельном выполнении путём изоляции состояния актора. ∙ Reactor (event-loop) — Обрабатывает параллельные события синхронно, помещая их в очередь и направляя зарегистрированным обработчикам. Реализует событийно-ориентированную асинхронную обработку поверх синхронного цикла событий. Часто применяется в системах с интенсивным I/O, упрощая управление конкурентными событиями. ∙ Proactor — Цикл событий, в котором операции начинаются пользовательским кодом, но завершаются внешним агентом (например, I/O подсистемой), который запускает обработчик завершения по завершении операции (возвращая данные в callback). ∙ И будет презентация курса Patterns 2025 👉 Сохраните себе ссылку на каталог паттернов с примерами кода: https://github.com/tshemsedinov/Patterns-JavaScript/tree/ru 👉 Подпишитесь на канал, чтобы не пропустить этот и следующие стримы: https://www.youtube.com/@TimurShemsedinov ∙ Готовлю также стрим по доступу к данным с обсуждением паттернов: Active Record, DAO, DTO, DAL, Repository, ORM, Query Builder, Transaction Script, Template Method

🧩 This and much more will be covered in Patterns 2025 course
const getTomorrowDate = () => {
  const timeout = 86400000;
  return new Promise((resolve) => {
    setTimeout(() => resolve(new Date()), timeout)
  });
};
// ⚡️ Electricity over IP, as defined in RFC 3251: https://datatracker.ietf.org/doc/html/rfc3251
const socket = new WebSocket('wss://lamp.local:3251');

socket.onopen = () => {
  socket.send(JSON.stringify({ voltage: 230, frequency: 50 }));
};

socket.onmessage = (e) => {
  const { voltage, frequency } = JSON.parse(e.data);
  console.log(`⚡️ Transferred: ${voltage}V @ ${frequency}Hz`);
};
const Coin = (v) => ({ map: (f) => Coin(f(v)) });
const flip = () => crypto.getRandomValues(new Uint8Array(1))[0];
Coin(flip()).map((r) => (r & 1 ? '🪙' : '💩')).map(console.log);
const findMeaningOfLife = () => {
  const offset = 0;
  const delay = Infinity;
  return new Promise((resolve) => {
    setTimeout(() => resolve(42 + offset), delay);
  });
};
['🥚', '🥚',  '🐓', '🥚', '🥚', '🥚'].toSorted()
class Coming {
  constructor() {
    return new Promise((resolve) => 
      setTimeout(() => {
        resolve(this);
      }, DAY_OF_JUDGMENT - Date.now())
    );
  }
}

const secondComing = await new Coming();
((<F extends () => void>(Function: F = {} as F) => Function())());
class Future {
  constructor() {
    const { name: key } = this.constructor;
    const value = void [].length;
    throw new Error(`${key} is ${value}`);
  }
}

new Future();

💡 Обновлен индекс открытого каталога паттернов - теперь там есть описание 1-2 строки, которые напомнит вам суть паттерна - добавлены паттерны не из GoF, но распространены в JavaScript и TypeScript - появилось больше ссылок на примеры https://github.com/tshemsedinov/Patterns-JavaScript/tree/ru

Мастер-класс "Паттерны в JavaScript и TypeScript" ⏰ Начало: сегодня, 22 марта в 15:00 (Киевское время) 👳 Тимур Шемсединов 🥷
Мастер-класс "Паттерны в JavaScript и TypeScript" ⏰ Начало: сегодня, 22 марта в 15:00 (Киевское время) 👳 Тимур Шемсединов 🥷 Илья Климов 🧔‍♂️ Дмитрий Нечай Регистрация через Телеграмм-бот: https://patterns-js.com/tpk6nh?traffic_mark=7k8x47&utm_source=organic&utm_medium=telegram2metarhia&utm_campaign=web

🧩 Запись стрима с регистрацией на мастер класс https://youtube.com/live/kw3UBUOAh0I Бесплатный мастер-класс "Паттерны в JavaScript и TypeScript" ⏰ Начало: в эту субботу 22 марта в 15:00 (Киевское время) Участники: 👳 Тимур Шемсединов 🥷 Илья Климов 🧔‍♂️ Дмитрий Нечай Регистрация через Телеграмм-бот: https://patterns-js.com/tpk6nh?traffic_mark=7k8x47&utm_source=organic&utm_medium=telegram2metarhia&utm_campaign=web

❓ В четверг 20 марта в 19:00 будет созвон сообщества Метархия, с выпускниками предыдущих наборов по паттернам, ноде и асинхронному программированию. Мы будем стримить его. Можно задать вопросы заранее и мы на них ответим. https://forms.gle/dDZTfR4P6AJFyHfB7

У кого не выходит выбрать язык на лендинге курса, можете сделать это в консоли, при помощи паттернов, самое базовое решение тут, но вы не останавливайтесь:
class Maybe {
  constructor(value) {
    this.value = value;
  }

  static of(value) {
    return new Maybe(value);
  }

  map(fn) {
    return this.value ? Maybe.of(fn(this.value)) : this;
  }

  getValue(defaultValue) {
    return this.value || defaultValue;
  }
}

class SelectCommand {
  constructor(selector, value) {
    this.selector = selector;
    this.value = value;
  }

  execute() {
    return Maybe.of(document.querySelector(this.selector))
      .map(el => (el.value = this.value, el))
      .map(el => el.dispatchEvent(new Event('change', { bubbles: true })))
      .getValue(null);
  }
}

const lang = 'RU'; // or UKR

new SelectCommand('.form-select-arrow', lang).execute();

🧩 Практический мастер-класс Паттерны в JavaScript и TypeScript ⏰ Начало: в эту субботу 2025-03-22 в 15:00 (Киевское время) 👳 Тимур Шемсединов 🥷 Илья Климов 🧔‍♂️ Дмитрий Нечай Изучение Патернов помогает: ✅ Писать более понятный код, который просто читать ✅ Эффективно оптимизировать JavaScript и TypeScript ✅ Быстрее и качественнее решать задачи ✅ Проектировать системы, которые просто изменять 🤖 Регистрация через Телеграмм-бот: https://patterns-js.com/0jiuic?traffic_mark=krzdaj

Скоро в метархии будет новый Emitter оптимизированый для V8, на него переедут протокод metacom, сервер приложений impress, и т.д. но вообще его полезно даже просто почитать: https://github.com/metarhia/metautil/blob/ee/lib/events.js
const ee = new Emitter();
ee.on('eventA', (data) => {
  console.log({ data });
  // Prints: { data: 'value' }
});
ee.emit('eventA', 'value');
const ee = new Emitter();
setTimeout(() => {
  ee.emit('eventA', 'value');
}, 100);
const result = await ee.toPromise('eventA');
const ee = new Emitter();
passReferenceSomewhere(ee);
const iterable = ee.toAsyncIterable('eventB');
for await (const eventData of iterable) {
  console.log({ eventData });
}



  listenerCount(eventName) {
    if (eventName) {
      return this.#events.get(eventName)?.length || 0;
    }
    const listeners = this.#events.values();
    return Array.from(listeners).reduce((acc, { length }) => acc + length, 0);
  }

  eventNames() {
    return Array.from(this.#events.keys());
  }
}

Скоро в Метархии будет оптимизированый для V8 новый Emitter, на который переедут стримы, протокод metacom, все другие части технологии, но его полезно даже просто пичитать: https://github.com/metarhia/metautil/blob/ee/lib/events.js
const DONE = { done: true, value: undefined };

class EventIterator {
  #resolvers = [];
  #emitter = null;
  #eventName = '';
  #listener = null;
  #onerror = null;
  #done = false;

  constructor(emitter, eventName) {
    this.#emitter = emitter;
    this.#eventName = eventName;

    this.#listener = (value) => {
      for (const resolver of this.#resolvers) {
        resolver.resolve({ done: this.#done, value });
      }
    };
    emitter.on(eventName, this.#listener);

    this.#onerror = (error) => {
      for (const resolver of this.#resolvers) {
        resolver.reject(error);
      }
      this.#finalize();
    };
    emitter.on('error', this.#onerror);
  }

  next() {
    return new Promise((resolve, reject) => {
      if (this.#done) return void resolve(DONE);
      this.#resolvers.push({ resolve, reject });
    });
  }

  #finalize() {
    if (this.#done) return;
    this.#done = true;
    this.#emitter.off(this.#eventName, this.#listener);
    this.#emitter.off('error', this.#onerror);
    for (const resolver of this.#resolvers) {
      resolver.resolve(DONE);
    }
    this.#resolvers.length = 0;
  }

  async return() {
    this.#finalize();
    return DONE;
  }

  async throw() {
    this.#finalize();
    return DONE;
  }
}

class EventIterable {
  #emitter = null;
  #eventName = '';

  constructor(emitter, eventName) {
    this.#emitter = emitter;
    this.#eventName = eventName;
  }

  [Symbol.asyncIterator]() {
    return new EventIterator(this.#emitter, this.#eventName);
  }
}

class Emitter {
  #events = new Map();
  #wrappers = new Map();
  #maxListeners = 10;

  constructor(options = {}) {
    this.#maxListeners = options.maxListeners ?? 10;
  }

  emit(eventName, value) {
    const listeners = this.#events.get(eventName);
    if (!listeners) return Promise.resolve();

    const promises = listeners.map((fn) => fn(value));
    return Promise.all(promises).then(() => undefined);
  }

  on(eventName, listener) {
    const listeners = this.#events.get(eventName) || [];
    if (listeners.includes(listener)) {
      throw new Error('Duplicate listeners detected');
    }
    listeners.push(listener);
    this.#events.set(eventName, listeners);

    if (listeners.length > this.#maxListeners) {
      throw new Error(
        `MaxListenersExceededWarning: Possible memory leak. ` +
          `Current maxListeners is ${this.#maxListeners}.`,
      );
    }
  }

  once(eventName, listener) {
    const wrapper = (value) => {
      this.off(eventName, listener);
      listener(value);
    };
    wrapper.origin = listener;
    this.on(eventName, wrapper);
    this.#wrappers.set(listener, wrapper);
  }

  off(eventName, listener) {
    if (!listener) return void this.clear(eventName);

    const listeners = this.#events.get(eventName);
    if (!listeners) return;

    const keep = (f) => f !== listener && f !== this.#wrappers.get(listener);
    const updated = listeners.filter(keep);

    this.#events.set(eventName, updated);
    this.#wrappers.delete(listener);
  }

  toPromise(eventName) {
    return new Promise((resolve) => {
      this.once(eventName, resolve);
    });
  }

  toAsyncIterable(eventName) {
    return new EventIterable(this, eventName);
  }

  clear(eventName) {
    if (!eventName) {
      this.#events.clear();
      this.#wrappers.clear();
      return;
    }
    const listeners = this.#events.get(eventName);
    if (!listeners) return;
    for (const listener of listeners) {
      this.#wrappers.delete(listener);
    }
    this.#events.delete(eventName);
  }

  listeners(eventName) {
    if (eventName) {
      const listeners = this.#events.get(eventName) || [];
      return listeners.map((listener) => listener.origin || listener);
    }
    return Array.from(this.#events.values()).flat();
  }

На что вы всегда найдете время?
Anonymous voting

Когда внук начал программировать на TypeScript, дедушка переписал на суслика свою квартиру
Когда внук начал программировать на TypeScript, дедушка переписал на суслика свою квартиру