Upload
max-klymyshyn
View
622
Download
5
Embed Size (px)
Citation preview
@maxmaxmaxmaxМАКСИМ КЛИМИШИНCTO ZAKAZ.UA
GVMachines Inc.
Изоморфный JavaScript
Обо мне
‣ 11+ лет опыта веб разработки, 5 лет JavaScript, 6 лет Python
‣ Работал в oDesk, Helios, 42cc.
‣ Со-организатор конференций PyCon Ukraine, KyivJS
‣ 3 года работаю техническим директором в ZAKAZ.UA
Что такое изоморфный код?
isomorphic
Возможность использовать один и тот же код
как на клиенте так и на сервере
ISOMORPHIC
СЕЙЧАС
CLIENT
API
SERVER
изоморфный код
Зачем это надо?
Проблемы one page apps
Зачем это надо?
‣ Производительность - загрузка данных, задержка при старте
‣ Тяжелая операция по рендерингу и созданию DOM-дерева
‣ Недружелюбные для краулеров (hashbang)
Проблемы архитектуры
Зачем это надо?
‣ Двойная валидация входных данных
‣ Поддержка сложной бизнес-логики одновременно на клиенте и на сервере
‣ Зависимость от сервера в мобильных приложениях
Изоморфный JavaScript может
решить эти проблемы
Зачем это надо?
Почему JavaScript?
Зачем это надо?
‣ Браузеры полноценно поддерживают только JavaScript
‣ Все.
Проблема
JavaScript
Основные преградыJavaScript
‣ Несовместимые с common.js библиотеки
‣ Плохая совместимость модулей (backward compatibility)
‣ Мало инструментов для контроля асинхронного кода
‣ Глобальное состояние и мутабельность объектов
Что уже есть?JavaScript
‣ React
‣ Meteor
‣ Derby
‣ Lazojs
‣ …
КУДА ДВИЖЕТСЯ
CLI
ENT
API
SERV
ER
изоморфный код
DATABASE CACHE
React Native теперь можно создавать мобильные приложения
МОБИЛЬНЫЕ
КУДА ДВИЖЕТСЯ
CLI
ENT
API
SERV
ERизоморфный код
DATABASE CACHE
MOBILE
Такое заинтересует кого угодно
Такое заинтересует кого угодно
AST, LLVM
Есть варианты решить эту проблему по другому
Abstract syntax treeAST
‣ pyjamas и другие - анализирует дерево python кода и создает код на front-end
‣ проблема с тем, что нужно добавлять runtime языка, который используется
‣ можно ограничить runtime, но с неполноценной поддержкой трудно
AST
PYTHON
RUBY
…
AST JAVASCRIPT
RUNTIME
LLVM – Low Level Virtual MachineLLVM
‣ emscripten – тулза для преобразования LLVM в JavaScript
‣ Он портиррует стек и т.д.
‣ Но если использовать вместе с Clojure Compiler, то код будет хорошо оптимизированным
‣ Python, Ruby и все языки LLVM в JavaScript
LLVM
PYTHON
RUBY
…
LLVM INTERMEDIATE JAVASCRIPT
RELOOPER ALGO
#include <stdio.h>int main(){ int sum = 0; for (int i = 1; i <= 100; i++) sum += i; printf("1+...+100=%d\n", sum); return 0;}
C
@.str = private constant [14 x i8] c"1+...+100=%d\0A\00"define i32 @main() { %1 = alloca i32, align 4 %sum = alloca i32, align 4 %i = alloca i32, align 4 store i32 0, i32* %1 store i32 0, i32* %sum, align 4 store i32 1, i32* %i, align 4 br label %2; <label>:2 %3 = load i32* %i, align 4 %4 = icmp sle i32 %3, 100 br i1 %4, label %5, label %12; <label>:5 %6 = load i32* %i, align 4 %7 = load i32* %sum, align 4 %8 = add nsw i32 %7, %6
store i32 %8, i32* %sum, align 4 br label %9; <label>:9 %10 = load i32* %i, align 4 %11 = add nsw i32 %10, 1 store i32 %11, i32* %i, align 4 br label %2; <label>:12 %13 = load i32* %sum, align 4 %14 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i32 %13)ret i32 0 }
LLVM assembly
function _main() { var __label__; var $1; var $sum; var $i; $1 = 0; $sum = 0; $i = 0; $2$2: while(1) { var $3 = $i; var $4 = $3 <= 100; if (!($4)) { __label__ = 2; break $2$2; } var $6 = $i;
var $7 = $sum; var $8 = $7 + $6; $sum = $8; var $10 = $i; var $11 = $10 + 1; $i = $11; __label__ = 0; continue $2$2; } var $13 = $sum; var $14 = _printf(__str, $13); return 0;}
Low-level JavaScript
function K() { var a, b; b = a = 0; a:for(;;) { if(!(b <= 100)) { break a } a += b; b += 1; } _printf(J, a); return 0; }
+ Closure Compiler
У подходов есть общая проблема – debugging
Clojure & ClojureScriptClojure
‣ Компилируется в JavaScript (как и в любой другой язык) потому синтаксис отсутствует
‣ Source Maps + полноценная имплементация рантайма на JavaScript – легко дебажить
‣ Неизменяемые структуры данных
ClojureScript
CLOJURESCRIPT JAVASCRIPT
CLOJURE RUNTIME
LispSyntax free
Следствием отсутствия синтаксиса – ~35 трансляторов/компиляторов/
интерпретаторов lisp-о подобных языков
OM
ClojureScript + OM(defn- render-fn* [] (let [js (doto (.getEngineByName (ScriptEngineManager.) "nashorn") ; React requires either "window" or "global" to be defined. (.eval "var global = this") (.eval (-> "public/assets/scripts/main.js" io/resource io/reader))) view (.eval js "omelette.view") render-to-string (fn [edn] (.invokeMethod ^Invocable js view "render_to_string" (-> edn list object-array)))] (fn render [title state-edn] (html5 [:head [:meta {:charset "utf-8"}] [:meta {:http-equiv "X-UA-Compatible" :content "IE=edge,chrome=1"}]
Изоморфный JS как отдельный сервис
А почему-бы не сделать отдельный сервис, который рендерит JavaScript где надо
Service
Service
‣ Синхронный сервис
‣ Очередь задач, асинхронно
Два варианта
Service
приложение
database cache node.js
rendered rendered
task 1
запрос 2
state
сервер задач node.js
запрос 1
state
task 2
cache
Выводы
Выводы
‣ Увеличивается количество shared кода, уменьшается рассеивание бизнес логики между разными платформами (клиент, сервер, мобильные)
‣ Улучшается UX – за счет пререндеринга пользователь получает картинку на экране быстрее
‣ Улучшается видимость в поисковых системах
‣ Не нужно все переписывать на JavaScript
Кто в темеВыводы
‣ Yahoo! Mail
‣ Walmart
‣ Airbnb
‣ Netflix
iForum 2015
@maxmaxmaxmax