Рубрики
Без рубрики

E ~ Wee ~ CTOR: писать крошечный эффектор с нуля # 1 – счетчик

Всем привет! Мне очень нравится «реализовать что-то с нуля» Тип статьи, например: потерян с … Помечено эффектор, графики, JavaScript.

Всем привет!

Мне очень нравится «Внедрить что-то с нуля» Тип статьи, например:

Это хороший способ узнать, как все работает, и раскрыть магию за черным ящиком библиотеки.

Я планирую написать маленький Эффектор ☄️. – подобная библиотека под названием Е ~ Wee ~. CTOR Отказ Это будет проект для образовательных целей.

  • Название «Eweific» получено из «эффектора» и «Wee», что означает «маленький, маленький, крошечный»
  • Второе значение «Wee» также соответствует
  • Также меня зовут Виктор, и мне нравится, как звучит «Eweific»:)

Хорошее и простое место для начала – это пример «счетчика» из Эффектор веб-сайт :

import {createStore, createEvent} from 'effector'

const add = createEvent()
const sub = createEvent()
const reset = createEvent()

const counter = createStore(0)
  .on(add, (count, n) => count + n)
  .on(sub, (count, n) => count - n)
  .reset(reset)

counter.watch(n => console.log('counter:', n))
// counter: 0
add.watch(n => console.log('add', n))
sub.watch(n => console.log('subtract', n))
reset.watch(() => console.log('reset counter'))

add(5)
// add 5
// counter: 5
sub(1)
// subtract 1
// counter: 4
reset()
// reset counter
// counter: 0

Таким образом, нам нужно реализовать два основных объекта – событие и магазин – и некоторые из их методов.

Теперь я не буду глубоко погрузиться в эффектор, если вы хотите сделать это, проверьте эту статью. Но вот некоторые основные моменты от архитектуры эффектора:

  • Эффектор внутри создает график узлов
  • Узлы (очевидно) ссылки на следующий график
  • Любой узел может содержать последовательность шагов для запуска
  • Шаг может одновременно изменять данные ввода или остановить вычисление отделения или запустить некоторую функцию побочных эффектов
  • После некоторого ядра эффектора события проходит входные данные в узле и запускает выполнение шагов, используя Алгоритм поиска по ширину
  • Любой высокоуровневый эффектор ( событие , Магазин , Эффект , Домен ) Это какой-то объект, прикрепленный к узлу или кучу узлов.

Вот график логических отношений для кода выше:

И вот какой эффектор создает, структурный граф узлов:

Давайте начнем с основной вещи графа – A Узел Отказ Узел должен содержать ссылки на следующие узлы – края графика и последовательность Шаги – Где мы опишем логику.

export const createNode = ({ next = [], seq = [] } = {}) => ({
  next,
  seq,
})

CreateNode Заводская функция очень проста, она просто создает объект узла и ничего другого. Мы могли бы даже пойти без него и описать узлы на месте, как простое предметы. Но фабрика функция дает нам два преимущества:

  • Каждый и каждый узел, который он возвращается, имеет ту же структуру Итак, мы не будем упустить несколько полей, определяющих их вручную
  • Синтаксис ES6 имеет очень удобное Параметры по умолчанию и Разрушение задания , и они могут взять нагрузку на назначение значений поля по умолчанию для узла

Следующее, что нам нужно, это шаги . Существует шесть типов шагов в эффектере, но мы начнем с одного. И мы даже не будем создавать завод для этого:) Давайте просто использовать Функция как шаг. С таким узлы будут содержать последовательность функций для выполнения.

Событие это самый простой эффекторный блок. Это функция, прикрепленная к узлу графа. Единственная цель события как объекта высокого уровня состоит в том, чтобы разместить входные данные в узел и начать цикл вычислений.

export const createEvent = () => {
  const event = payload => launch(event, payload)
  event.graphite = createNode()
  return event
}

CreateeeVent Фабрика создает функцию и прикрепляет узел графа в его графит поле. Создано событие -функция принимает входные данные и выполняет функцию запуск . Это запуск Функция начнет вычислительный цикл, и мы опишем его позже, когда мы пишем ядро.

Как видите, узел, прикрепленный к событию, не имеет никакого Следующий узлы, ни Шаги Отказ

Прежде чем написать ядро, давайте реализуем Смотреть Функциональность.

Смотреть это вспомогательный узел, который запускает побочный эффект. В случае нашего счетчика пример этот побочный эффект – console.log Отказ

export const watch = unit => fn => {
  const node = createNode({
    seq: [fn],
  })
  unit.graphite.next.push(node)
}

Смотреть Функция принимает два аргумента (в значении функционального программирования) – единица Чтобы прикрепить Смотреть Узел и функция для выполнения.

Поскольку мы решили использовать простые функции как шаги (на данный момент) – мы просто будем использовать данную функцию побочных эффектов в качестве шага для Смотреть узел.

И после создания Смотреть Узел, мы положили этот узел на Следующий массив для данного устройства.

И теперь давайте добавим .watch Метод нашему событие :

export const createEvent = () => {
  const event = payload => launch(event, payload)
  event.graphite = createNode()
+  event.watch = watch(event)
  return event
}

Таким образом, мы сможем смотреть события:

const event = createEvent()
event.watch(data => console.log(data))

И здесь мы идем:) Ядро Отказ Это не так пугающее, как это звучит, правда. Есть две основные части ядра: очереди и Цикл вычислений Отказ

Эффектор использует пять очередей. Начнем с одного:

// contains objects { node, value }
const queue = []

Цикл вычисления пересекает график и выполняет каждый шаг из каждого узла:

const exec = () => {
  while (queue.length) {
    let { node, value } = queue.shift()
    node.seq.forEach(step => (value = step(value)))
    node.next.forEach(node => queue.push({ node, value }))
  }
}

Простые слова функция Exec Может быть описан как следующие шаги:

  1. В то время как очередь не пусто, предпринять элемент из очереди
  2. Выполните каждый шаг из узла, с начальным значением из элемента очередей
  3. Положите каждый узел из Следующий массив в очередь, с новым значением
  4. Перейти к 1.

Еще одна вещь – нам нужна функция запуск Для наших событий:

export const launch = (unit, value) => {
  queue.push({ node: unit.graphite, value })
  exec()
}

запуск Функция просто ставит Узел и ценность в очередь и запускает вычислительный цикл. Вот и все.

И Последнее, но не менее важное – A магазин Отказ

export const createStore = defaultState => {
  let currentState = defaultState
  const store = {}

  store.graphite = createNode({
    seq: [value => (currentState = value)],
  })

  return store
}

Createstore Фабрика создает объект и прикрепляет узел графа в его графит Поле, как и с событием. Но магазин Узел имеет один шаг – он сохраняет входные данные в прилагаемую переменную Текущее состояние .

Нам также нужно реализовать несколько методов магазина, как .на , .reset и .смотреть . Давайте начнем с последнего:

  store.watch = fn => {
    fn(currentState)
    return watch(store)(fn)
  }

.watch Способ для хранения немного отличается, чем для события – впервые его называется, он выполняет заданную функцию с текущим состоянием, а затем создает Смотреть узел.

  store.on = (event, fn) => {
    const node = createNode({
      next: [store.graphite],
      seq: [value => fn(currentState, value)],
    })
    event.graphite.next.push(node)
    return store
  }

.на Метод принимает событие (или любую единицу) и функцию редуктора. Как .watch метод Это создает новый на Узел, с одним шагом, где вызывается редуктор. И помещает этот новый узел до магазин Узел на графике, поэтому новое значение от редуктора будет сохранено в магазин узел. Также это ставит этот новый узел Следующий массив для данного события (или единицы).

  store.reset = event => store.on(event, () => defaultState)

.reset Метод просто ярлык для установки исходного состояния.

И мы сделали первый шаг в этом путешествии. Если мы объединяем все эти части вместе, мы получим минимальный рабочий «эректор», который мог бы запустить счетчик пример. А что важнее – это следует эффектному архитектуре!

В следующих главах мы вырастем наш младенца. Я постараюсь прикрыть все эффекторные API в разумных пределах, поэтому оставаться настроенными;)

Я создал Проект на Github Чтобы помочь вам последовать исходным кодом. Все код, описанный в этой главе, совершено в Это совершает Отказ

Спасибо за чтение!

Оригинал: “https://dev.to/effector/e-wee-ctor-writing-tiny-effector-from-scratch-1-1kap”