Применение к области видимости
Важно обратить внимание, если вы изменяете какой-либо объект, лежащий внутри области видимости, из-за пределов AngularJS, необходимо всегда вызывать метод $scope.$apply.
2.1.3 Связывание данных
AngularJS предлагает концепцию связывания данных (data binding), работающую в обе стороны. Однако следует обратить внимание на то, что центровым объектом связывания данных всегда является область видимости. Только объекты, находящиеся внутри области видимости, могут участвовать в связывании данных.
Как это работает
Представим себе простую html разметку с полем ввода, к которому привязана переменная, лежащая внутри области видимости, автоматически созданной AngularJS (это не глобальная область видимости). ngModel является директивой, которая меняет поведение того или иного элемента DOM. В данном случае, эта директива связывает содержимое input и переменную в области видимости. Это не магия, это не более чем директива, которую вы легко можете реализовать самостоятельно, однако разработчики уже реализовали её, потому что такое поведение требуется очень часто.
Чисто технически, директива добавляет обработчик события изменения введённого в input значения, в котором производит вызов $scope.$apply для изменения переменной в области видимости, а также применяет обработчик $scope.$watch на области видимости, в котором меняется значение в поле ввода.
К примеру, попробуем ввести в поле ввода любой текст и понаблюдать, как изменяется выводимый текст. При этом можем открыть консоль и ввести $scope.yourName = "test", обратите внимание, что текст и значение в поле ввода не изменились, так как AngularJS ничего не знает про консоль и не может отследить изменения, произведённые из неё. Теперь введите $scope.$apply() и изменения обработаются AngularJS.
Важно обратить внимание на то, что любые события браузера вызываются вне области видимости AngularJS, поэтому внутри ваших обработчиков таких событий необходимо вызывать $scope.$apply.
2.1.4 Внедрение зависимостей
Внедрение зависимостей (dependency injection, DI) является третьим краеугольным камнем AngularJS, однако он не относится непосредственно к логике работы библиотеки, а скорее к организации кода.
Грубо говоря, DI позволяет любой функции сказать: «мне нужны эти сервисы, эти и эти», после чего AngularJS автоматически предоставит эти сервисы, где бы они ни были реализованы и где бы ни находились. Разумеется, это работает только в пределах AngularJS.
Сервис в DI — не более, чем некоторый объект, который предоставляет некоторую функциональность. Это может быть что угодно, от простой константы до фабрики классов.
2.1.5 Построение приложения в AngularJS
Теперь можно поговорить о том, как описанные выше концепции работают вместе для реализации приложений.
Каркас и ng-app
Вся библиотека AngularJS разбита на независимые модули, соответственно от вашего приложения ожидается такая же организация и для этого предоставлено всё необходимое.
ngApp это директива, сообщающая AngularJS: «здесь находится приложение». DOM, окружённый элементом с этой директивой будет работать под управлением AngularJS.
Создание модуля
Для начала сообщим AngularJS, что мы хотим не просто создать приложение, а подключить к нему собственную функциональность:
<!doctype html> <html ng-app="tutorial"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script> </head> <body> <div> <label>Имя:</label> <input type="text" ng-model="yourName"> <hr> <h1>Привет, { {yourName } }!</h1> </div> </body> </html> |
Само приложение является просто модулем, давайте создадим его (важно: имя модуля должно совпадать со значением, переданным директиве ngApp):
var app = angular.module("tutorial", [])
Обратите внимание на эту запись, поскольку она является стандартной для всех элементов AngularJS. В особенности обратите внимание на второй параметр-массив. Это — зависимости для DI, и везде, где возможно внедрение зависимостей такая запись является предпочтительной, хотя возможны и другие варианты.
Общая форма внедрения зависимостей выглядит так:
["dependency1", "dependency2", ..., function(dependency1, dependency2, ...) {}]
Что важно, имена параметров функции, в которую внедряются зависимости, могут быть любыми, важен лишь их порядок. Это позволяет пользоваться программами для сжатия кода, не боясь, что что-то перестанет работать.
Второй вариант, который можно использовать для обучения и в тех случаях, когда код не сжимается, выглядит так:
function(dependency1, dependency2, ...) {}
В данном случае наоборот, важны имена параметров, а не их порядок. В первом случае мы передаём имена в виде строк, которые не будут изменены при сжатии кода, во втором случае имена извлекаются из параметров функции, поэтому изменение имени параметра будет иметь плачевные последствия.
Настройка провайдеров
Провайдер — это функция, которая отвечает за создание сервисов. Если требуется перед внедрением сервиса в функцию настроить его функциональность, следует обращаться к провайдеру. Наличие/отсутствие провайдера у сервиса определяется целиком и полностью его разработчиком.
app.config(["$locationProvider", function($locationProvider) { // обратите внимание, что я сохранил название параметра // это полезно для читаемости кода $locationProvider.html5Mode(true) }]) |
В примере выше мы настроили работу сервиса $location, включив режим html5. Теперь приложение будет работать с полноценными URL, без использования хэшей, если браузер поддерживает HTML5 History API. Аналогичным образом настраиваются другие сервисы.
MVC
MVC в AngularJS реализовано отдельным модулем и не играет важной роли в самой библиотеке. Вы можете пользоваться любой сторонней реализацией, или разработать собственную.
Для включения MVC в 1.1.5 не требуется дополнительных действий. В 1.1.6 (и 2.0) потребуется подключить angular-router.js и в зависимости приложения добавить ngRoute:
var app = angular.module("tutorial", ["ngRoute"])
ngRoute настраивается с помощью $routeProvider, например, так:
app.config(["$routeProvider", function($routeProvider) { $routeProvider.when("/", { templateUrl: "/partials/index.html", controller: "defaultCtrl" }) }]) |
Подробнее о том, что здесь происходит, вы можете прочитать в документации к модулю ngRoute или в справке по $route на сайте AngularJS.
Модели
Как таковых, моделей в AngularJS нет. Использованная выше ngModel — не более чем директива, меняющая поведение DOM, а model лишь удобное имя. Вы можете использовать к примеру модели Backbone.js, а можете вообще запрашивать данные с сервера вручную или пользоваться модулем ngResource (читайте документацию $http и $resource).
Важно помнить, что всё связывание данных происходит исключительно на области видимости. Поместили модель в область видимости? Всё отлично работает.
Контроллеры
В отличие от моделей, концепция контроллеров в AngularJS есть, однако относятся контроллеры здесь непосредственно к DOM. Рассмотрим пример:
<!doctype html> <html ng-app="tutorial"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script> </head> <body> <div ng-controller="defaultCtrl"> <label>Имя:</label> <input type="text" ng-model="yourName"> <hr> <h1>Привет, { { yourName } }!</h1> <button ng-click="sayHello(yourName)">Сказать привет</button> </div> </body> </html> |
И код контроллера (заодно узнаем, как они создаются):
app.controller("defaultCtrl", ["$scope", function($scope) { $scope.sayHello = function (name) { alert("Привет, " + name); } }]) |
В контроллер необходимо внедрить хотя бы $scope, в противном случае он будет вещью в себе и не сможет ничего сделать с областью видимости, а именно для этого предназначен контроллер. Однако в 2.0 предлагается новый, упрощённый вариант создания контроллеров:
<!doctype html> <html ng-app="tutorial"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script> </head> <body> <div ng-controller="defaultCtlr as ctrl"> <label>Имя:</label> <input type="text" ng-model="yourName"> <hr> <h1>Привет, { { yourName } }!</h1> <button ng-click="ctrl.sayHello(yourName)">Сказать привет</button> </div> </body> </html> |
app.controller("defaultCtrl", function() { this.sayHello = function (name) { alert("Привет, " + name); } }) |
Обратите внимание, способы не равнозначны. И this.yourName не будет равен $scope.yourName. Однако второй способ позволяет вообще не внедрять $scope в контроллер и очистить код от ненужных зависимостей. Кроме того функции контроллера не будут зависеть от $scope и их можно будет использовать в других частях приложения, а не только в одной конкретной области видимости (по этой же причине рекомендуется передавать в функции контроллера параметры, а не полагаться на $scope).
2.2 Фреймворк MeteorJS
Метеор написан на Node JS и позволяет создавать приложения, где практически стерта грань между серверной и клиентской частью. Код пишется в одном стиле как для клиента, так и для сервера. Благодаря этому, основное внимание уделяется самой логике приложения. Больше не возникают проблемы, по поводу связи клиента и сервера. Скорость написания веб-приложений ощутимо возрастает. Javascript everywhere!
Можно выделить 7 основных принципов Метеора:
1) Передача только данных. Больше никакой разметки не передается в запросах. Отправляются лишь данные с серверной части, а клиент уже рендерит их как хочет.
2) Один язык (JavaScript). На сервере и клиенте один и тот же язык, думаю плюсы очевидны.
3) База данных доступна отовсюду. Закончились те времена, когда к БД обращались только с сервера. Теперь можно обращаться прям с клиентской части приложения.
4) Компенсация задержки. На клиенте используется предварительная выборка и имитация модели, таким образом связь с БД происходит практически мгновенно.
5) Полный набор реактивности. Создаем риал-тайм приложения по дефолту. Все слои, от БД до шаблонов имеют доступный событийный интерфейс.
6) Общая экосистема фреймворка. Метеор с открытым исходным кодом и объединяет, но не заменяет другие open source инструменты и frameworks.
7) Простота = производительность. Лучший способ проще делать то, что кажется простым. Все делается через понятный и прозрачный API.
2.2.1 Основные понятия MeteorJS
Meteor — веб-платформа на языке JavaScript, предназначенная для разработки Web-приложений реального времени. Для связи с современными браузерами используется протокол Distributed Data Protocol (DDP), поддерживаемый с помощью WebSocket'ов, либо, если поддержки веб-сокетов и DDP нет — AJAX.
Код Meteor работает поверх node.js (однако он не придерживается принятой в node.js асинхронной модели, что может затруднить интеграцию node.js и meteor-приложений). Ядром Meteor является протокол DDP. Он предназначен для работы с коллекциями JSON-документов, позволяя легко создавать, обновлять, удалять, запрашивать и просматривать их. По умолчанию в качестве хранилища таких документов используется MongoDB.
Фактически, Meteor обеспечивает две базы данных MongoDB: буферную базу данных со стороны клиента и базу данных MongoDB со стороны сервера. Когда пользователь вносит изменения в данные — например, нажав кнопку Сохранить, — код JavaScript, выполняемый в браузере, обновляет соответствующую запись в локальной базе данных MongoDB, а затем делает запрос DDP к серверу. Код обрабатывается немедленно, как будто операция выполнена успешно, потому что ответа сервера ждать не нужно. Тем временем данные на сервере обновляются в фоновом режиме. Если операция на сервере не удалась, или возвращается неожиданный результат, то код JavaScript на стороне клиента немедленно корректирует данные в соответствии с последним ответом сервера. Эта корректировка называется компенсацией задержки и обеспечивает дополнительное ощущение быстродействия у пользователя.
Даже система шаблонов Meteor явно нацелена на упрощение связи в режиме реального времени. На большинстве Web-платформ в код можно легко внедрять язык гипертекстовой разметки (HTML) — или разметки, эквивалентной HTML, такой как HTML Abstraction Markup Language (Haml). Это позволяет легко вставлять в страницы, отправляемые пользователю, динамические значения из базы данных. После этого система должна следить за изменениями в данных и обновлять разметку. Однако система шаблонов в Meteor регистрирует, к каким именно данным обращались через шаблон, и автоматически выполняет обратные вызовы, изменяя этот HTML-код при изменении соответствующих данных, что делает шаблоны реального времени простыми и быстрыми.
Одна из важнейших особенностей платформы состоит в том, что она позволяет использовать один и тот же код как на стороне сервера, так и на стороне клиента. Между сервером и клиентом, как правило, передаются данные, а не HTML-код.
2.2.2 Реактивность
Реактивное программирование — парадигма программирования, ориентированная на потоки данных и распространение изменений. Это означает, что должна существовать возможность легко выражать статические и динамические потоки данных, а также то, что выполняемая модель должна автоматически распространять изменения сквозь поток данных.
А теперь перейдем не посредственно к MeteorJS. Если коллекции - это центральный компонент Meteor, то реактивность - оболочка, благодаря которой этот компонент становится полезным.
Коллекции радикально преобразуют способ работы приложения с изменением данных. У нас больше нет необходимости проверять изменения вручную (например, через AJAX вызов), а затем применять их к HTML, - изменения данных сами могут поступать в любое время, и Meteor будет плавно применять их к пользовательскому интерфейсу.
Просто задумайтесь об этом ненадолго: за кулисами Meteor способен изменить любую часть вашего пользовательского интерфейса при обновлении лежащей в его основе коллекции.
Императивным способом сделать это будет использование .observe(), - функции курсора, которая вызывает коллбеки (callbacks - функции-обработчики события) при изменении соответствующих данному курсору документов. Далее с помощью этих коллбеков можно преобразовать DOM (отрисованный HTML нашей web-страницы). В итоге код будет выглядеть как-то так:
Вы, возможно, уже поняли, что такой код очень быстро станет запутанным. Представьте, что вам нужно будет иметь дело с изменениями для каждого атрибута поста и заменять сложный HTML внутри соответствующего <li> элемента. Не говоря уже обо всех замысловатых крайних случаях, которые могут возникнуть, когда мы начнем полагаться на разные источники информации, способные изменяться в реальном времени.
Использование описанного выше образца иногда необходимо, особенно в случае работы со сторонними виджетами. Например, давайте представим, что мы хотим в реальном времени добавлять или убирать отметки на карте в зависимости от данных в коллекции (скажем, чтобы отображать местоположение пользователей, находящихся в системе). В таких случаях нужно будет использовать коллбеки observe(), чтобы карта “разговаривала” с Meteor коллекцией и знала, как реагировать на изменения данных. К примеру, вы будете полагаться на коллбеки added и removed для вызова собственных методов API карты dropPin() или removePin().
2.2.3 Декларативный подход
Meteor предоставляет нам лучший способ - реактивность, которая, по существу, является примером применения декларативного подхода. Декларативность позволяет нам один раз определить отношение между объектами и знать, что они будут синхронизированы, вместо того, чтобы указывать поведение для каждого возможного изменения.
Это очень мощная концепция, потому что функционирующая в реальном времени система имеет много входных данных, способных изменяться в непредсказуемый момент. В Meteor декларативным образом определяется то, как нужно отрисовывать HTML в зависимости от состояния интересующих нас реактивных источников данных. Благодаря этому Meteor может позаботиться о мониторинге таких источников и взять на себя запутанную работу по поддержанию пользовательского интерфейса в актуальном состоянии.
А если покороче, то вместо того, чтобы думать о коллбеках observe, благодаря Meteor мы можем писать:
Затем получаем список постов, используя:
За кулисами Meteor настраивает коллбеки observe() за нас и перерисовывает соответствующие секции HTML при изменении реактивных данных.
2.2.4 Отслеживание зависимостей в Meteor: вычисления.
Хотя Meteor является реактивным фреймворком, работающим в реальном времени, не весь код внутри приложения реактивный. Если бы это было так, то все приложение перезапускалось бы каждый раз, когда что-нибудь изменяется. Вместо этого реактивность ограничена отдельными областями кода, которые называют вычислениями(computations).
Другими словами, вычисление - это блок кода, который исполняется каждый раз, когда изменяется один из реактивных источников данных, от которых он зависит. Если у вас есть реактивный источник данных (например, переменная сессии) и вы хотите на него реактивно отзываться, вам нужно установить для него вычисление.
Заметьте, что обычно вам не нужно это делать напрямую, потому что Meteor сам добавляет для каждого отрисованного шаблона и хелпера их собственное вычисление (значит, вы можете быть уверены в том, что шаблоны будут реактивно отображать свои источники данных).
Каждый реактивный источник данных отслеживает все использующие его вычисления, чтобы сообщать им об изменении своего значения. Для этого он вызывает на вычислении функцию invalidate().
Вычисления, как правило, установлены таким образом, чтобы просто пересматривать свое содержимое в случае инвалидации, - это как раз то, что происходит с вычислениями шаблонов (хотя они используют дополнительные трюки, чтобы перерисовывать страницу более эффективно). Несмотря на то, что вы можете при необходимости усилить контроль над тем, что именно ваши вычисления делают при инвалидации, на практике вы почти всегда будете использовать этот механизм.
Теперь когда мы понимаем теорию, которая стоит за вычислениями, было бы неплохо создать одно из них. Мы можем использовать функцию Tracker.autorun, чтобы заключить блок кода внутри вычисления и сделать его реактивным:
Обратите внимание, что нам нужно поместить блок Tracker внутри Meteor.startup(), чтобы убедиться, что он исполняется только после того, как Meteor закончил загружать коллекцию Posts.
За кулисами autorun затем создает вычисление и настраивает его, чтобы пересматривать содержимое при изменении источников данных, от которых он зависит. Мы установили простое вычисление, которое печатает в консоль количество постов. Так как Posts.find() - реактивный источник данных, он позаботится о том, чтобы сообщать вычислению о необходимости пересмотра содержимого каждый раз, когда количество постов изменяется.
Теперь мы можем писать код, который использует реактивные данные очень естественным образом, зная, что система зависимостей позаботится о его перезапуске в нужный момент.
2.2.5 Построение приложения в MeteorJS
Для начало нужно установить MeteorJS с помощью утилиты curl (утилита работает только для Linux & Mac, так же на Windows при использовании терминалов unix-подобных, на официальном сайте посмотреть иную установку для Windows), Напишем команду:
curl https://install.meteor.com | /bin/sh
После чего MeteorJS будем скачен и установлен, теперь можем приступить к созданию приложения, пишем:
meteor create myapp
Запускаем проект локально:
cd myapp
meteor
=> Meteor server running on: http://localhost:3000/
Теперь можно перейти в браузер и написать http://localhost:3000/, после чего откроется приложение (todo).
Удаляем все файлы в папке нашего приложения, напишем простой пример живого шаблона HTML. Meteor очень шустро рендерит шаблоны HTML и мгновенно отображает измененные данные. Пример кода:
var fragment = Meteor.render(
function () {
var name = Session.get("name") || "Anonymous";
return "<div>Hello, " + name + "</div>";
});
document.body.appendChild(fragment);
Session.set("name", "Bob"); // страница обновится автоматически
Кроме того можно использовать свои шаблоны типа Handlebars или Jade.
В html шаблоны выглядят так:
<template name="userInfo">
<p>Hello {{ username }}</p>
</template>
Атрибут name обязателен, по нему осуществляется обращение через JS API:
Template.userInfo({username: "Awesome man!"});
Шаблоны инклудятся в другой шаблон или html:
<body>
<div>
{{> userInfo}}
</div>
</body>
Можно передать функцию, которая вычислится и вернет результат:
Template.players.topScorers = function () {
return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};
<template name="players">
{{#each topScorers}}
<div>{{name}}</div>
{{/each}}
</template>
События для шаблона описываются так:
Template.playerScore.events({
'click .givePoints': function () {
Users.update(this._id, {$inc: {score: 2}});
}
});
<template name="playerScore">
<div>{{name}}: {{score}}
<span class="givePoints">Give points</span>
</div>
</template>
Все чисто и декларативно.
Метеор имеет встроенную систему пакетов. Пакеты это отдельные Javascript программы. Они могут внедрять код в клиентскую или серверную часть. Или содержать библиотеку новых функций. Благодаря им можно самим расширять возможности фреймворка, похожи на модули в Node JS.
Примеры пакетов:
· Coffeescript пакет - позволяет писать код для Метеора на Coffeescript.
· jQuery и Backbone пакеты, позволяют включить эти же библиотеки в приложение. Такого же эффекта можно добиться, просто скопирнув эти библиотеки в папку lib.
Просмотреть все доступные на данный момент пакеты можно командой: meteor list
API пакетов пока находится в разработке и не описано нигде.
3. Цель исследований, проблемы и гипотезы
3.1 Цель исследований, постановка научного эксперимента
В виду динамичного развития сферы веб возникла необходимость относительной стандартизации, максимальной оптимизации и упрощения как в разработке так и в использовании веб-сайта как разработчиком так и конечным пользователем.
Именно поэтому целью исследования стал весма актуальный вопрос, а именно определение самого удобного и самого доступного из фреймворков для создания веб-сайта. При этом в иследовании необходимо также уделить внимание аспекту возможности объединения фреймворков в одно приложение и определения влияния такого объединения на структуру, сложность написания кода, читаемость (понимания) кода, доступность документации к каждому фреймворку и конечный резыльтат.
Подобная практика является довольно редкой, потому информации о таковой практически нет в публичном доступе, ибо как каждый программист самостоятельно и индивидуально прописывает связку между фреймворками в прямой зависимости от поставленых целей и нужд.
Объектами исследования были выбранны два самых популярных на сегодня фреймворка. Первым стал MeteorJS, который привлекает разработчика своей доступностью, оболочной и back-end’ом NodeJS. Вторым было выбрано AngularJS, который является самым популярным фрейворком на данный момент времени. Как описывал ранее - в его минусах была документация, но за годы использования данного фреймворка людьми собралось сообщество, которое постоянно дополняет документацию и описывают решения популярных проблем в разработке приложений. Такая документация не является официальной и ее нельзя найти на официальном сайте производителя данного фреймворка. Но в достаточном количестве и с самыми актуальными замечаниями ее можно найти на ресурсах для разработчиков.
При постановке эксперимента, было написано однотипное приложения в каждом фреймворке, и проведен сравнительный анализ структуры и быстродействия работы приложения в каждом из них. После чего было проведено построение того же приложения, с использования двух фреймворков в одном приложении, при этом необходимо было определиться за какие из дача будет отвечать каждый из фреймворков, а это и обработка событий, и рендер представления, и работа с базой данных, и роутинг, и шаблоны и так же back-end.
При реализации данного подхода возникнет ряд, на первый взгляд, не подлежащих решению проблем. Самые типичные проблемы: конфликты, отладка, быстродействие, производительность, - все эти проблемы возможно устранить, но не сразу, не на начальной стадии разработки. Решения проблем отводится на конечные стадии разработки, когда проблема проявит себя в полном объеме.
3.2 Метод исследования
Методы исследования будут применены к оценке использования ресурсов, к размеру приложения, к масштабируемости приложения, сюда же будет входить структура приложения и написания кода. Методы могут быть почти любого рода тестирования приложений WEB.
3.3 Проект веб-сайта для эксперимента
Для проектирования веб-сайта было выбрано ряд критерий, а именно:
– простота, но, при этом, сам сайт должен был функционально полноценен, чтобы можно было сделать сравнения и анализ его
- back-end - неотъемлемая часть функционального приложения, которая работает с базой данных, обработкой потоковых данных и т.д.
Идея приложения заключалась в том, чтобы пользователь, мог самостоятельно создавать заметки, при этом получить доступ к ним с любого устройства в любой точке доступа Интернет. Так же необходимо обеспечить пользователя возможностью устанавливать напоминания на заметки, предоставлять доступ другим пользователям к определенным группам заметок, либо конкретным выбранным заметкам.
Структурой приложения было выбрано «Навигация в трёх столбцах»
Структура была избранна по критерию просты, так как хотелось больше места уделить именно графическим заметкам, которые должны быть красивые, привлекающие внимание и при этом понятные. Для этого нужно было обеспечить достаточно места и было решено сделать выдвигающею навигацию аккаунта, чтобы графическим заметкам не было тесно.
В первый блок «Навигация аккаунта» было добавленный следующий функционал:
· Регистрация / авторизация пользователя
· Редактирования личных данных
· Импорт / экспорт заметок
· Настройка уведомлений
· Настройка публичного доступа
· Выход
Ко второму блоку входили сами заметки. К каждой заметке можно было выбирать дизайн их или самому сделать оригинальный дизайн и далее, можно было поделиться собственным дизайном для его дальнейшего использования другими пользователями. Продолжая тему заметок: для каждой заметки можно было установить пароль удаления (это часть функционала публичного доступа), можно было добавить напоминая, выбирания избранных заданий либо покупок и т.д., выбор количества отображенных заметок в ряду, редактирования, удаления, размеры, приоритеты заметок и подобного мелкого функционала.
В последнем блоке были размещены сами заметки списком, к ним был добавлен поиск, который искал по всему:
- по дате (год, месяц, день, час, минута) заметки;
- по ключевым словам в заметки, по заголовку;
- по приоритету;
- по статусу – это относиться к заметкам которые имеют какие задачи выполнения;
- по другим критериям.
Так же была добавленная сортировка заметок, которою можно было отсортировать по тем же признакам что и поиск.
4. Реализация и итоги исследования
4.1 Описание реализации исследований
Фрагменты кода для каждого фреймворков один функционал (добавления заметок)
· Регистрация / авторизация пользователя
4.2 Сравнительный анализ фреймворков
Розгянем код з 4.1 порівнюєм
4.3 Верификация гипотезы исследований
После иссле. Мы видим проблемы в каждом фремворке.. по средствам объединения получаэм униврса. Фреймворм, опис проблем (что они решаемые)
Время разработки, но при этом … отвечающим требования сайт.
liblary:
Информация о методологии и онлайн книга: https://smacss.com/
Русскоязычный перевод книги по SMACSS: https://github.com/andrew--r/smacss
Более полная информация о методологии: https://ru.bem.info/
http://webstudio2u.net/ru/webdesign/354-site-develop-methods.html
http://webonto.ru/internet-tehnologii-chto-eto-takoe/
http://knowledge.allbest.ru/programming/3c0b65625a3bc78b5d53b89421316c36_0.html
http://www.lessons-tva.info/edu/e-inf3/m3t3_1.html
https://habrahabr.ru/post/273795/
https://habrahabr.ru/post/266081/
http://ru.discovermeteor.com/chapters/reactivity/
http://www.ibm.com/developerworks/ru/library/wa-meteor/