SlideShare une entreprise Scribd logo
1  sur  217
Télécharger pour lire hors ligne
Перепись приложения. Нативного.Перепись приложения. Нативного.
На JS. DoneНа JS. Done
Тимофей Лавренюк
@geek_timofey
1
О себеО себе
2
О проектеО проекте
3 . 1
3 . 2
Архитектура
3 . 3
Архитектура
3 . 3
ЯдроЯдро
Архитектура
3 . 3
ЯдроЯдро
RPC ServerRPC ServerАрхитектура
3 . 3
ЯдроЯдро
А что умеет?А что умеет?
3 . 4
ЯдроЯдро
Работа с локальной БДА что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БДА что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БД
Общение с RPC-сервером
А что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БД
Работа с PDFОбщение с RPC-сервером
А что умеет?А что умеет?
3 . 4
Настал 2017 годНастал 2017 год
3 . 5
Настал 2017 годНастал 2017 год
Нужна web-версия...
3 . 5
СРОЧНО НУЖНАСРОЧНО НУЖНА
WEB-ВЕРСИЯ !!!11WEB-ВЕРСИЯ !!!11 3 . 6
3 . 7
WEB-ВерсияWEB-Версия
1.01.0
3 . 8
Старая архитектура
3 . 9
SPASPA
Старая архитектура
3 . 9
SPASPA
REST APIREST API
ЯдроЯдро
Старая архитектура
3 . 9
SPASPA
REST APIREST API
ЯдроЯдро
RPC ServerRPC ServerСтарая архитектура
3 . 9
Старая WEB-версия
3 . 10
Не было режима автораНе было режима автора
Старая WEB-версия
3 . 10
Не было режима автораНе было режима автора
Зависило от интернетЗависило от интернет
соединениясоединения
Старая WEB-версия
3 . 10
Не было режима автораНе было режима автора
Зависило от интернетЗависило от интернет
соединениясоединения
Был PHPБыл PHP
Старая WEB-версия
3 . 10
3 . 11
Полноценное web-приложениеПолноценное web-приложение
Задача:Задача:
3 . 12
Полноценное web-приложениеПолноценное web-приложение
Задача:Задача:
Не уступающее нативным клиентам
3 . 12
3 . 13
Увидел PHP
3 . 14
Пришлось переписать
веб приложение
3 . 15
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Работает в OfflineРаботает в Offline
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Работает в OfflineРаботает в Offline
Не уступает нативнымНе уступает нативным
клиентамклиентам
Новая WEB-версия
3 . 16
Криптография
Offline + Web Worker Работа с PDFОбщение с RPC-сервером
Framework Progressive Web App
4
КриптографияКриптография
5 . 1
Основная проблемаОсновная проблема
5 . 2
Основная проблемаОсновная проблема
Никто не знает как работает шифрование в проекте
5 . 2
5 . 3
5 . 4
5 . 5
RSARSA
AESAES
Основные алгоритмы
5 . 6
RSARSA
5 . 7
AESAES
cipher = encrypt(block, key) // шифруем block с помощью key
block = decrypt(cipher, key) // расшифровываем cipher с помощью key
5 . 8
Как реализовать алгоритмыКак реализовать алгоритмы
шифрования?шифрования?
5 . 9
5 . 10
JS библиотека
5 . 10
JS библиотека
Web Crypto API
5 . 10
JS библиотека
Web Crypto API
OpenSSL -> WebAssembly
5 . 10
JS библиотекаJS библиотека
5 . 11
JS библиотекаJS библиотека
+ Изоморфный код
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
- Производительность
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
- Производительность
- Размер
5 . 11
Web Crypto APIWeb Crypto API
5 . 12
Web Crypto APIWeb Crypto API
+ Размер
5 . 12
Web Crypto APIWeb Crypto API
+ Размер
+ Производительность
5 . 12
Web Crypto APIWeb Crypto API
- Неполная поддержка RSA
+ Размер
+ Производительность
5 . 12
Web Crypto APIWeb Crypto API
- Неполная поддержка RSA
- Изоморфный код
+ Размер
+ Производительность
5 . 12
Алгоритм PBKDF2Алгоритм PBKDF2
5 . 13
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
+ Производительность
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
+ Производительность
- Размер
5 . 14
JS библиотекаJS библиотека
5 . 15
Node-ForgeNode-Forge
JS библиотекаJS библиотека
5 . 15
Node-ForgeNode-Forge
JS библиотекаJS библиотека
Про улучшение оптимизации - в следующих слайдах...
5 . 15
NodeForge FailsNodeForge Fails
5 . 16
Offline + Web WorkerOffline + Web Worker
6 . 1
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
ФайлыФайлы
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
ФайлыФайлы
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
7 . 1
Service WorkerService Worker
7 . 2
7 . 3
7 . 3
{
"globDirectory": "dist",
"globPatterns": [
"index.html",
"*.js",
"assets/**/*.{png,svg}",
"assets/*.{png,svg}"
],
"swSrc": "src/service-workers/main.worker.js",
"swDest": "dist/service-worker.js"
}
workbox.config.js
7 . 4
{
"assets": [
"src/assets",
"src/service-workers",
"src/manifest.json",
{
"glob": "workbox-sw.js",
"input": "node_modules/workbox-sw/build",
"output": "./workbox-3.5.0"
},
{
"glob": "workbox-core.dev.js",
"input": "node_modules/workbox-core/build/",
"output": "./workbox-3.5.0"
},
{
"glob": "workbox-precaching.dev.js",
"input": "node_modules/workbox-precaching/build/",
"output": "./workbox-3.5.0"
}
],
}
angular.json
7 . 5
importScripts('workbox-3.5.0/workbox-sw.js');
workbox.setConfig({
debug: true,
modulePathPrefix: 'workbox-3.5.0/'
});
workbox.skipWaiting();
workbox.clientsClaim();
workbox.precaching.precacheAndRoute([]);
main.worker.js
7 . 6
workbox injectManifest
7 . 7
workbox injectManifest
workbox.precaching.precacheAndRoute([
{
"url": "index.html",
"revision": "4f8109353581284e76b88e568d642376"
},
{
"url": "0.js",
"revision": "2af14762103b4c1f18e620bd30a53d2e"
},
{
"url": "main.js",
"revision": "ef2fb7f5913e6614c9ee3621ad299d1b"
}
])
service-worker.js
7 . 7
СтатикаСтатика
7 . 8
Данные пользователяДанные пользователя
8 . 1
Service WorkerService Worker
8 . 2
Persistent StoragePersistent Storage
8 . 3
8 . 4
LocalStorageLocalStorage
8 . 4
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
CookiesCookies
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Deprecated
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Deprecated
IndexedDBIndexedDB
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Deprecated
IndexedDBIndexedDB
Большой лимит
Хорошая поддержка
Не Deprecated
LocalStorageLocalStorage Небольшой лимит
8 . 4
IndexedDBIndexedDB
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом
выполнение операций происходит асинхронновыполнение операций происходит асинхронно
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом
выполнение операций происходит асинхронновыполнение операций происходит асинхронно
умеет хранить JS-объекты и блобыумеет хранить JS-объекты и блобы
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом
выполнение операций происходит асинхронновыполнение операций происходит асинхронно
имеет жутко неудобное низкоуровневое APIимеет жутко неудобное низкоуровневое API
умеет хранить JS-объекты и блобыумеет хранить JS-объекты и блобы
8 . 5
https://caniuse.bitsofco.de/embed/index.html?
feat=indexeddb&periods=future_2,future_1,current&accessible-
colours=false
ПоддержкаПоддержка
8 . 6
DebugDebug 8 . 7
IndexedDB в боюIndexedDB в бою
9 . 1
9 . 2
1. Открыть или создать базу
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
2. Создать Schema
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
2. Создать Schema
open.onupgradeneeded = () => {
const db = open.result;
const store = db.createObjectStore("MyObjectStore", {keyPath: "id"});
const index = store.createIndex("NameIndex", ["name.last", "name.first"]);
};
9 . 2
9 . 3
3. Создать транзакцию
9 . 3
3. Создать транзакцию
open.onsuccess = () => {
const db = open.result
const tx = db.transaction("MyObjectStore", "readwrite")
const store = tx.objectStore("MyObjectStore");
const index = store.index("NameIndex");
}
9 . 3
4. Запросить данные
3. Создать транзакцию
open.onsuccess = () => {
const db = open.result
const tx = db.transaction("MyObjectStore", "readwrite")
const store = tx.objectStore("MyObjectStore");
const index = store.index("NameIndex");
}
9 . 3
4. Запросить данные
const getJohn = store.get(12345); // по id
const getBob = index.get(["Smith", "Bob"]); // через index
3. Создать транзакцию
open.onsuccess = () => {
const db = open.result
const tx = db.transaction("MyObjectStore", "readwrite")
const store = tx.objectStore("MyObjectStore");
const index = store.index("NameIndex");
}
9 . 3
9 . 4
5. Получить данные
9 . 4
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = () => {
console.log(getBob.result.name.first); // => "Bob"
};
9 . 4
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = () => {
console.log(getBob.result.name.first); // => "Bob"
};
5. Закрыть транзакцию
9 . 4
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = () => {
console.log(getBob.result.name.first); // => "Bob"
};
5. Закрыть транзакцию
tx.oncomplete = function() {
db.close();
};
9 . 4
Boilerblate!!!1Boilerblate!!!1
9 . 5
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить документ
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить документ
Скудная сортировка
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить документ
Скудная сортировка
Auto-commit транзакций
9 . 6
"Никто не использует IndexedDB в чистом виде"
- Все JS-разработчики
9 . 7
"Никто не использует IndexedDB в чистом виде"
- Все JS-разработчики
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API 9 . 7
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
DB EngineDB Engine
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
Idb
ZangoDb
MiniMongo
jsStore
PouchDB
Dexie
LocalForage
DB EngineDB Engine
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
Idb
ZangoDb
MiniMongo
jsStore
PouchDB
Dexie
LocalForage
DB EngineDB Engine
YDN-DB
AlaSQL
Lovefield
9 . 8
9 . 9
9 . 10
КроссбраузерностьКроссбраузерность
9 . 10
КроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
9 . 10
SQL-подобный APISQL-подобный APIКроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
9 . 10
SQL-подобный APISQL-подобный API
select, insert, update, delete
group by, order by, limit, skip
join
КроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
9 . 10
SQL-подобный APISQL-подобный API
select, insert, update, delete
group by, order by, limit, skip
join
КроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
Отличная производительностьОтличная производительность
Оптимизация и анализ запросов
9 . 10
Создание SchemaСоздание Schema
9 . 11
Создание SchemaСоздание Schema
const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0);
schemaBuilder.createTable('Documents')
.addColumn('id', lf.Type.STRING)
.addColumn('parentId', lf.Type.OBJECT)
.addColumn('type', lf.Type.STRING)
.addColumn('signOrder', lf.Type.NUMBER)
.addColumn('encryptionKey', lf.Type.STRING)
.addIndex('idxSignOrder', ['signOrder'], false, lf.Order.DESC);
.addPrimaryKey(['id']);
schemaBuilder.connect().then((db) => {
// Можно работать с базой
});
9 . 11
Создание SchemaСоздание Schema
const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0);
schemaBuilder.createTable('Documents')
.addColumn('id', lf.Type.STRING)
.addColumn('parentId', lf.Type.OBJECT)
.addColumn('type', lf.Type.STRING)
.addColumn('signOrder', lf.Type.NUMBER)
.addColumn('encryptionKey', lf.Type.STRING)
.addIndex('idxSignOrder', ['signOrder'], false, lf.Order.DESC);
.addPrimaryKey(['id']);
schemaBuilder.connect().then((db) => {
// Можно работать с базой
});
9 . 11
Типы полейТипы полей
9 . 12
Типы полейТипы полей
String
9 . 12
Типы полейТипы полей
String
Number
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
Date
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
Date
Array Buffer
9 . 12
SQL-подобный APISQL-подобный API
SQL Lovefield
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(document)
.where(document.type.eq('TEMPLATE'))
.exec()
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(document)
.where(document.type.eq('TEMPLATE'))
.exec()
SELECT encryptionKey
FROM Documents
WHERE signOrder >= 1
ORDER BY signOrder DESC
LIMIT 10
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(document)
.where(document.type.eq('TEMPLATE'))
.exec()
SELECT encryptionKey
FROM Documents
WHERE signOrder >= 1
ORDER BY signOrder DESC
LIMIT 10
Database
.select(document.encryptionKey)
.from(document)
.where(document.signOrder.gte(1))
.orderBy(document.signOrder, lf.Order.DESC)
.limit(10)
.exec()
9 . 13
SQL Lovefield
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document, file)
.where(lf.op.and(
document.fileId.eq(file.id),
document.id.eq('123'),
))
.exec()
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document, file)
.where(lf.op.and(
document.fileId.eq(file.id),
document.id.eq('123'),
))
.exec()
SELECT * FROM document
INNER JOIN file
ON document.fileId = file.id
WHERE document.id = '123'
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document, file)
.where(lf.op.and(
document.fileId.eq(file.id),
document.id.eq('123'),
))
.exec()
SELECT * FROM document
INNER JOIN file
ON document.fileId = file.id
WHERE document.id = '123'
Database
.select()
.from(document)
.innerJoin(
file,
document.fileId.eq(file.id)
)
.where(document.id.eq('123'))
.exec()
9 . 14
function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) {
var openCursorRequest1 = index1.openCursor(keyRange1);
var openCursorRequest2 = index2.openCursor(keyRange2);
assert(index1.objectStore === index2.objectStore);
var primKey = index1.objectStore.keyPath;
var set = {};
var resolved = 0;
function complete() {
if (++resolved === 2) onfinish();
}
function union(item) {
var key = JSON.stringify(item[primKey]);
if (!set.hasOwnProperty(key)) {
set[key] = true;
onfound(item);
}
}
openCursorRequest1.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
union(cursor.value);
} else {
complete();
}
}
openCursorRequest2.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
union(cursor.value);
} else {
complete();
}
}
}
Чистый API
9 . 15
function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) {
var openCursorRequest1 = index1.openCursor(keyRange1);
var openCursorRequest2 = index2.openCursor(keyRange2);
assert(index1.objectStore === index2.objectStore);
var primKey = index1.objectStore.keyPath;
var set = {};
var resolved = 0;
function complete() {
if (++resolved === 2) onfinish();
}
function union(item) {
var key = JSON.stringify(item[primKey]);
if (!set.hasOwnProperty(key)) {
set[key] = true;
onfound(item);
}
}
openCursorRequest1.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
union(cursor.value);
} else {
complete();
}
}
openCursorRequest2.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
union(cursor.value);
} else {
complete();
}
}
}
Чистый API
9 . 15
Интересные особенностиИнтересные особенности
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Firebase
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Firebase
Поддерживает Import/Export в Javascript-объект
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Firebase
Поддерживает Import/Export в Javascript-объект
Поддерживает Data Observation
9 . 16
Data ObservationData Observation
9 . 17
Data ObservationData Observation
var query = db.select()
.from(documents)
.where(documents.id.eq('1'));
var handler = function(changes) {
// Будет вызываться всегда, когда происходит изменение данных
};
db.observe(query, handler);
db.update(documents)
.set(documents.title, 'New Title')
.where(documents.id.eq('1'))
.exec();
db.unobserve(query, handler);
9 . 17
НюансыНюансы
9 . 18
Изменение SchemaИзменение Schema
9 . 19
Вывод ошибокВывод ошибок
9 . 20
Вывод ошибокВывод ошибок
Constraint error: (202) Attempted to insert NULL value to non-nullable field
Documents.signOrder.
9 . 20
Хранение файловХранение файлов
10 . 1
10 . 2
ArrayBuffer
10 . 2
Offline + Web WorkerOffline + Web Worker
11 . 1
11 . 2
FrameworkFramework
12 . 1
АрхитектураАрхитектура
12 . 2
Redux + Side Effects + Entities + Selectors
12 . 3
Side EffectsSide Effects
@Effect()
documentCreate$ = this.actions$.pipe(
ofType(DocumentActions.Types.DocumentCreate),
map(action => action.payload.query),
exhaustMap(query =>
this.dbService.createDocument(query)
),
flatMap(() => [
new DocumentAction.DocumentCreateSuccess();
new DocumentAction.GenerateDocumentPreview();
])
);
12 . 4
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Document> {
activeDocumentId: number | null;
}
12 . 5
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Document> {
activeDocumentId: number | null;
}
export const adapter: EntityAdapter<Document> = createEntityAdapter<Document>();
12 . 5
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Document> {
activeDocumentId: number | null;
}
export const adapter: EntityAdapter<Document> = createEntityAdapter<Document>();
12 . 5
Entity adapterEntity adapter
addOne
addMany
addAll
removeOne
removeMany
removeAll
updateOne
updateMany
upsertOne
upsertMany
map
12 . 6
SelectorsSelectors
export const getDocumentState = (state: AppState) => state.documents;
export const getDocumentEntities = (state: DocumentState) => state.entities;
export const getDocumentEntities = createSelector(
getDocumentState,
getDocumentEntities
);
export const getAllDocuments = createSelector(getDocumentEntities, entities =>
Object.keys(entities).map(id => entities[id])
);
12 . 7
BoilerplateBoilerplate
12 . 8
SchematicsSchematics
ng generate action
store
entity
reducer
effect
container
feature
12 . 9
class GetDocumentPreviewAction implements IDocumentAction {
readonly type = DocumentActionTypes.GetDocumentPreview;
documentType: DocumentType;
constructor(public payload: any) { }
}
class GetDocumentPreviewSuccessAction implements IDocumentAction {
readonly type = DocumentActionTypes.GetDocumentPreviewSuccess;
documentType: DocumentType;
constructor(public payload: IFileWithData) { }
}
class GetDocumentPreviewFailureAction implements IDocumentAction {
readonly type = DocumentActionTypes.GetDocumentPreviewFailure;
documentType: DocumentType;
}
12 . 10
https://github.com/pelotom/unionize
import { unionize, ofType, UnionOf } from 'unionize';
const DocumentActions = unionize({
GET_DOCUMENT_PREVIEW: ofType<{ id: string }>(),
GET_DOCUMENT_PREVIEW_SUCCESS: ofType<IFileWithData>()
GET_DOCUMENT_PREVIEW_FAILURE: {}
});
type DocumentAction = UnionOf<typeof DocumentActions>;
12 . 11
Коммуникация с Web WorkerКоммуникация с Web Worker
12 . 12
12 . 13
Effect
12 . 13
Effect
Action
12 . 13
Effect
Action
ReduxRedux
12 . 13
Effect
Action
ReduxRedux
12 . 13
Effect
Action
ReduxRedux ComutterComutter
12 . 13
Effect
Action
ReduxRedux ComutterComutter
12 . 13
Effect
Action
ReduxRedux Web WorkerComutterComutter
12 . 13
Effect
Action
ReduxRedux Web WorkerComutterComutter
12 . 13
Effect
Action
ReduxRedux Web Worker
Success/Failure
Action
ComutterComutter
12 . 13
Effect
Action
ReduxRedux Web Worker
Success/Failure
Action
ComutterComutter
12 . 13
Redux Devtools
12 . 14
ВыводыВыводы
13 . 1
13 . 2
Спасибо за вниманиеСпасибо за внимание
Тимофей Лавренюк
@geek_timofey
14

Contenu connexe

Tendances

Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
Ontico
 
Devconf2013 new-features-in-mysql-and-mariadb
Devconf2013 new-features-in-mysql-and-mariadbDevconf2013 new-features-in-mysql-and-mariadb
Devconf2013 new-features-in-mysql-and-mariadb
Sergey Petrunya
 
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Ontico
 
Архитектура HAWQ / Алексей Грищенко (Pivotal)
Архитектура HAWQ / Алексей Грищенко (Pivotal)Архитектура HAWQ / Алексей Грищенко (Pivotal)
Архитектура HAWQ / Алексей Грищенко (Pivotal)
Ontico
 
Распространенные ошибки применения баз данных (Сергей Аверин)
Распространенные ошибки применения баз данных (Сергей Аверин)Распространенные ошибки применения баз данных (Сергей Аверин)
Распространенные ошибки применения баз данных (Сергей Аверин)
Ontico
 
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
Ontico
 

Tendances (20)

Приключения проекта от компьютера разработчика до серьезных нагрузок / Андрей...
Приключения проекта от компьютера разработчика до серьезных нагрузок / Андрей...Приключения проекта от компьютера разработчика до серьезных нагрузок / Андрей...
Приключения проекта от компьютера разработчика до серьезных нагрузок / Андрей...
 
Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
Ошибки проектирования высоконагруженных проектов / Максим Ехлаков (OneTwoRent)
 
Андрей Ситник
Андрей СитникАндрей Ситник
Андрей Ситник
 
Хайлоад и безопасность в мире DevOps: совместимы ли? / Юрий Колесов (security...
Хайлоад и безопасность в мире DevOps: совместимы ли? / Юрий Колесов (security...Хайлоад и безопасность в мире DevOps: совместимы ли? / Юрий Колесов (security...
Хайлоад и безопасность в мире DevOps: совместимы ли? / Юрий Колесов (security...
 
Быстрое построение backendов c помощью реактивных потоков
Быстрое построение backendов c помощью реактивных потоковБыстрое построение backendов c помощью реактивных потоков
Быстрое построение backendов c помощью реактивных потоков
 
Devconf2013 new-features-in-mysql-and-mariadb
Devconf2013 new-features-in-mysql-and-mariadbDevconf2013 new-features-in-mysql-and-mariadb
Devconf2013 new-features-in-mysql-and-mariadb
 
Serghei Iakovlev "Chaos engineering in action"
Serghei Iakovlev "Chaos engineering in action"Serghei Iakovlev "Chaos engineering in action"
Serghei Iakovlev "Chaos engineering in action"
 
Как сделать сложное простым. История создания Проект1917 / Сергей Спорышев (I...
Как сделать сложное простым. История создания Проект1917 / Сергей Спорышев (I...Как сделать сложное простым. История создания Проект1917 / Сергей Спорышев (I...
Как сделать сложное простым. История создания Проект1917 / Сергей Спорышев (I...
 
MySQL: чек-лист для новичка в highload (Cвета Cмирнова, Aнастасия Распопина ...
MySQL:  чек-лист для новичка в highload (Cвета Cмирнова, Aнастасия Распопина ...MySQL:  чек-лист для новичка в highload (Cвета Cмирнова, Aнастасия Распопина ...
MySQL: чек-лист для новичка в highload (Cвета Cмирнова, Aнастасия Распопина ...
 
Дмитрий Стогов
Дмитрий СтоговДмитрий Стогов
Дмитрий Стогов
 
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
 
Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...
Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...
Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...
 
Архитектура HAWQ / Алексей Грищенко (Pivotal)
Архитектура HAWQ / Алексей Грищенко (Pivotal)Архитектура HAWQ / Алексей Грищенко (Pivotal)
Архитектура HAWQ / Алексей Грищенко (Pivotal)
 
Zabbix в Badoo или о чем не пишут в мануале, Илья Аблеев (Badoo)
Zabbix в Badoo или о чем не пишут в мануале, Илья Аблеев (Badoo)Zabbix в Badoo или о чем не пишут в мануале, Илья Аблеев (Badoo)
Zabbix в Badoo или о чем не пишут в мануале, Илья Аблеев (Badoo)
 
Практические примеры использования API в инфраструктурных продуктах Cisco для...
Практические примеры использования API в инфраструктурных продуктах Cisco для...Практические примеры использования API в инфраструктурных продуктах Cisco для...
Практические примеры использования API в инфраструктурных продуктах Cisco для...
 
Attacking MongoDB
Attacking MongoDBAttacking MongoDB
Attacking MongoDB
 
Распространенные ошибки применения баз данных (Сергей Аверин)
Распространенные ошибки применения баз данных (Сергей Аверин)Распространенные ошибки применения баз данных (Сергей Аверин)
Распространенные ошибки применения баз данных (Сергей Аверин)
 
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
Хорошо поддерживаемое в продакшне приложение / Николай Сивко (okmeter.io)
 
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...
 
Денис Иванов
Денис ИвановДенис Иванов
Денис Иванов
 

Similaire à Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10

И снова разработка под iOS. Павел Тайкало
И снова разработка под iOS. Павел ТайкалоИ снова разработка под iOS. Павел Тайкало
И снова разработка под iOS. Павел Тайкало
Stanfy
 
Истинный DevOps. Секрет 42.
Истинный DevOps. Секрет 42.Истинный DevOps. Секрет 42.
Истинный DevOps. Секрет 42.
Nikita Borzykh
 
Конструктор / Денис Паясь (Яндекс)
Конструктор / Денис Паясь (Яндекс)Конструктор / Денис Паясь (Яндекс)
Конструктор / Денис Паясь (Яндекс)
Ontico
 
Работа со статикой в Django
Работа со статикой в DjangoРабота со статикой в Django
Работа со статикой в Django
MoscowDjango
 
Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"
Andrew Mayorov
 
Sphinx. настройка, эксплуатация
Sphinx. настройка, эксплуатацияSphinx. настройка, эксплуатация
Sphinx. настройка, эксплуатация
andreyborue
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...
Vyacheslav Nikulin
 
JavaScript on frontend and backend (in Russian
JavaScript on frontend and backend (in RussianJavaScript on frontend and backend (in Russian
JavaScript on frontend and backend (in Russian
Mikhail Davydov
 

Similaire à Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 (20)

И снова разработка под iOS. Павел Тайкало
И снова разработка под iOS. Павел ТайкалоИ снова разработка под iOS. Павел Тайкало
И снова разработка под iOS. Павел Тайкало
 
My Open Source (Sept 2017)
My Open Source (Sept 2017)My Open Source (Sept 2017)
My Open Source (Sept 2017)
 
Node.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаNode.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчика
 
Истинный DevOps. Секрет 42.
Истинный DevOps. Секрет 42.Истинный DevOps. Секрет 42.
Истинный DevOps. Секрет 42.
 
Что нового в MySQL 8.0? / Дмитрий Ленев (Oracle)
Что нового в MySQL 8.0? / Дмитрий Ленев (Oracle)Что нового в MySQL 8.0? / Дмитрий Ленев (Oracle)
Что нового в MySQL 8.0? / Дмитрий Ленев (Oracle)
 
Diplom 1
Diplom 1Diplom 1
Diplom 1
 
Денис Паясь
Денис ПаясьДенис Паясь
Денис Паясь
 
Python Meetup
Python Meetup Python Meetup
Python Meetup
 
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
 
So Your WAF Needs a Parser
So Your WAF Needs a ParserSo Your WAF Needs a Parser
So Your WAF Needs a Parser
 
Конструктор / Денис Паясь (Яндекс)
Конструктор / Денис Паясь (Яндекс)Конструктор / Денис Паясь (Яндекс)
Конструктор / Денис Паясь (Яндекс)
 
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
 
Работа со статикой в Django
Работа со статикой в DjangoРабота со статикой в Django
Работа со статикой в Django
 
Scala, SBT & Play! for Rapid Application Development
Scala, SBT & Play! for Rapid Application DevelopmentScala, SBT & Play! for Rapid Application Development
Scala, SBT & Play! for Rapid Application Development
 
Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"
 
Oracle NoSQL Database
Oracle NoSQL DatabaseOracle NoSQL Database
Oracle NoSQL Database
 
Sphinx. настройка, эксплуатация
Sphinx. настройка, эксплуатацияSphinx. настройка, эксплуатация
Sphinx. настройка, эксплуатация
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...
 
JavaScript on frontend and backend (in Russian
JavaScript on frontend and backend (in RussianJavaScript on frontend and backend (in Russian
JavaScript on frontend and backend (in Russian
 
Node JS проблемы надежности, и пути их решения
Node JS проблемы надежности, и пути их решенияNode JS проблемы надежности, и пути их решения
Node JS проблемы надежности, и пути их решения
 

Plus de OdessaFrontend

Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
OdessaFrontend
 

Plus de OdessaFrontend (20)

Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19
 
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
 
Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19
 
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
 
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
 
Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17
 
Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17
 
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
 
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
 
Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16
 
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
 
Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16
 
Современный станок верстальщика
Современный станок верстальщикаСовременный станок верстальщика
Современный станок верстальщика
 
Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15
 
DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15
 
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
 
Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15
 
Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14
 
Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13
 
Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13
 

Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10