Тимофей Лавренюк
Архитектура
Криптография
Работа с локальной БД
Работа с PDF
Общение с RPC-сервером
Нужна web-версия...
Старая WEB-версия
Старая архитектура
Написать веб приложение так, как будто нет интернет соединения
Новая WEB-версия
Архитектура веб приложения
{
"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
{
"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
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
workbox injectManifest
workbox.precaching.precacheAndRoute([
{
"url": "index.html",
"revision": "4f8109353581284e76b88e568d642376"
},
{
"url": "0.js",
"revision": "2af14762103b4c1f18e620bd30a53d2e"
},
{
"url": "main.js",
"revision": "ef2fb7f5913e6614c9ee3621ad299d1b"
}
])
service-worker.js
Нет гибкости
FileWriter deprecated
WATTT??
Deprecated
Большой лимит
Хорошая поддержка
Не Deprecated
Небольшой лимит
cd ~Library/Application\ Support/Firefox/Profiles/xxxxxxxx.default/
storage/default/https+++app.keepsolid.com/idb
~Library/Safari/Databases/___IndexedDB/http_localhost_4200/KEEPSOLID_SIGN_DB
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"]);
};
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");
}
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();
};
"Никто не использует IndexedDB в чистом виде"
- Все JS-разработчики
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) => {
// Можно работать с базой
});
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()
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()
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
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);
Constraint error: (202) Attempted to insert NULL value to non-nullable field Documents.signOrder.
const document = {
id: 1,
name: 'Test'
}
myWorker.postMessage(document);
const newDocument = clone({
id: 1,
name: 'Test'
})
myWorker.postMessage(JSON.stringify(newDocument));
передача данных от одного контекста другому
const encoder = TextEncoder('utf-8');
const decoder = TextDecoder('utf-8');
const uInt8Array = encoder.encode('Some string');
const decodedString = decoder.decode(uInt8Array);
var uInt8Array = stringToUintArray(JSON.stringify(result));
myWorker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
но не все так плохо...
ArrayBuffer
var fileReader = new FileReader();
fileReader.onload = (event) => {
const arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);
const blob = new Blob([arrayBuffer]);
const objectUrl = URL.createObjectURL(blob);
blob:https://app.keepsolid.com/d45b2410-ad60-45be-9359-3f43524698db
Main Thread
Web Worker Thread
const sharedBuffer = new SharedArrayBuffer(2);
const arr = new Int8Array(sharedBuffer);
arr[0] = 42;
myWorker.postMessage(sharedBuffer);
Должны вернуться в V8 в конце 2018
Effect
Action
Web Worker
Success/Failure Action
Redux Devtools
Браузер | Лимит |
---|---|
Chrome | < 6% |
Firefox | < 10% |
Safari | < 50mb |
Edge | В зависимости от обьема HDD |
IE11 | < 250mb |
navigator.storage.estimate().then(estimate => {
// estimate.quota - сколько доступно памяти
// estimate.usage - сколько байт хранилища используется
});
indexedDB == null
Storage Usage == 0
Все работает
Все работает
Браузер | Метод |
---|---|
Chrome | LRU |
Firefox | LRU |
Safari | Отсутствует |
Edge | Отсутствует |
navigator.storage.persist().then(function(persistent) {
if (persistent)
// Браузер не будет чистить Storage
else
// Браузер очистит Storage в случае нехватки памяти
}
Firefox
window.addEventListener('online', () => {
// Есть интернет соединение
});
window.addEventListener('offline', () => {
// Отсутствует интернет соединение
});
navigator.onLine //true, false
navigator.effectiveType // 2g, 3g, 4g
Windows-версия KeepSolid Sign
Тимофей Лавренюк
@geek_timofey