uz
Feedback
HowProgrammingWorks - JavaScript and Node.js Programming

HowProgrammingWorks - JavaScript and Node.js Programming

Kanalga Telegram’da o‘tish

Программная инжененрия для 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

Ko'proq ko'rsatish
6 468
Obunachilar
-224 soatlar
-167 kunlar
-1130 kunlar
Postlar arxiv
🧩 В субботу (12 апреля) в 15:00 cтрим Data access patterns На этом канале 👉 https://www.youtube.com/@TimurShemsedinov Разбор паттернов и подходов: - Repository и Active Record - Query Builder и Object-Relational Mapping (ORM) - Value Object и Null Object - Data transfer object (DTO) - Data access object (DAO) и Data Access Layer (DAL) - Patterns: SAGA, Transaction Script и др. Для кого эфир? - Начинающие разработчики - Опытные инженеры - Тех-лиды, тим-лиды - Самоучки без CS-образования Кто ведет? 👳 Тимур Шемсединов - в представлении не нуждается 🧔‍♂️ Николай Белочуб - 10+ лет в Продуктовой Разработке, Senior SWE, OSS Contributor 🤵 Дмитрий Нечай - Chief Architect в PLATMA, CTO в HandyAI Программа курса по паттернам: https://nodeua.com/Patterns-2025.html

В 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