Изоморфный JavaScript (iForum 2015)

Preview:

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

Кто в темеВыводы

‣ Facebook

‣ Instagram

‣ Yahoo! Mail

‣ Walmart

‣ Airbnb

‣ Netflix

iForum 2015

@maxmaxmaxmax

Recommended