Реактивная Разработка

С использованием микро-фреймворков

Общая проблема производительности в Web разработке

При использовании популярных инструментов

aka angular, ember. jquery, etc..

Проблема

  1. При изменении части массива, или любого из элементов.
  2. При  изменении данных глубоко внутри элемента.

Низкая производительность при работе с динамичными  массивами и множеством вложенных в них элементов.

.controller('ctrl', function($scope) {
  $scope.array = [
    { deep: [...] },
    { deep: [...] }
  ];
});

В этом примере - происходит полный ре-рендер всего массива, при:

пример: angular

VirtualDOM

  • Модификация работает с элементами глубоко внутри дерева
  • Модификация только частей в которых изменились данные
  • Высокая производительность.

Примеры библиотек построенных на VirtualDOM:

React, Mithril, Virtual-DOM, Inferno, Bobril

Общий принцип работы Virtual-DOM

  • createElement - создание элемента
  • Diff Nodes - сравнение v-nodes , получение различий.
  • Patch Root Node - модификация основного узла новыми данными.

Микро-фреймворки

Отличительная особенность - компактный размер, высокая производительность и набор возможностей для выполнения различных задач.

Востребованы когда необходимо написать шустрый компонент, который должен быть быстрым, компактным без лишней траты ресурсов.

Mithril

/*  Класс компонента */
class Component {
  constructor(opts) {
    /* связывание экземпляра с даными инициализации... */
    this.opts = opts;

    /* связать функции с областью экземпляра */
    this.controller = this.controller.bind(this);
    this.view = this.view.bind(this);
  }

  /* контроллер компонента */
  controller(props) {
    return {
      paramOne: this.opts.paramOne
    };
  }

  /* метод отрисовки компонента*/
  view(ctrl, props, children) {
    return (
      <button onclick={() => someAction}
              attr={ctrl.paramOne} />
    );
  }
};

/* инициализация компонента - целевым объектом компонента назначаем экземпляр */
m.mount(document.body, new Component({ paramOne: 'Hello!' }));

пример: базовый компонент, ООП, msx

Достоинства: компактный (20kb minify) mvc фреймворк, с простым легковесным API, для быстрой разработки. Есть поддержка JSX. Подходит для компонентов, с неглубоким уровнем вложения, с практичной расширяемостью.

Inferno

import { Component } from `inferno-component`;

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0
    }
  }
  render() {
    return (
      <div>
        <h1>Заголовок!</h1>
        <span>Счетчик на: { this.state.counter }</span>
      </div>
    )
  }
}

InfernoDOM.render(<MyComponent />, document.body);

пример: базовый компонент, ООП, inferno-jsx

Достоинства: компактная (2.8kb minify) библиотека, основанная по девизу "маленькое но шустрое", библиотека подходит для разработке очень маленьких компонентов с различным функционалом, и имеющая оболочку для хранения состояний, и данных.

Virtual-DOM

import { h, diff, patch, createElement } = "virtual-dom";

function render(count)  {
  return h('div', {
    style: {
      lineHeight: (100 + count) + 'px',
      height: (100 + count) + 'px',
      width: (100 + count) + 'px',
      border: '1px solid red',
      textAlign: 'center'
    }
  }, [String(count)]);
}

var count = 0;

var tree = render(count); 
var rootNode = createElement(tree);
document.body.appendChild(rootNode);

setInterval(function () {
      count++;

      var newTree = render(count);
      var patches = diff(tree, newTree);
      rootNode = patch(rootNode, patches);
      tree = newTree;
}, 1000);

пример: базовый компонент

Достоинства: самодостаточный набор функций для работы с vdom, не предоставляет оболочку для работы с состояниями, или любой другой функционал - главная цель работы дать базовые инструменты работы с узлами: createElement, Diff, Patch. Подходит если вы хотите сами выполнить действие напрямую в контекст DOM, или написать свою оболочку.

Bobril

var BasicApp;
(function (BasicApp) {
    function p() {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i - 0] = arguments[_i];
        }
        return { tag: "p", children: args };
    }
    b.init(function () {
        b.invalidate();
        return [
            { tag: "h1", children: "First Bobril sample" },
            p("Uptime: ", b.uptime().toFixed(0), "ms Frame: ", 
              "" + b.frame(), " Frame duration:" + b.lastFrameDuration(), 
              " ms FPS:", (b.frame() * 1000 / b.uptime()).toFixed(1))
        ];
    });
})(BasicApp || (BasicApp = {}));

пример: базовый компонент

Достоинства:очень шустрый фреймворк, изначально основанный на mithril, с полным набором всевозможного сахара - роутер, свайпы, drag-n-drop, media query detection. Позиционирует себя как маленький инструмент со всеми необходимыми возможностями которые могут потребоваться при разработке.

Тесты производительности

Made with Slides.com