Slide 1

Slide 1 text

Promise — это не больно! Михаил Давыдов, JavaScript-разработчик 2013 год, FrontTalks

Slide 2

Slide 2 text

Асинхронность везде!

Slide 3

Slide 3 text

Запросы к серверу 03

Slide 4

Slide 4 text

© 2013 NAVTEQ Ошибка на карте? · Условия использования Данные пользователя 04

Slide 5

Slide 5 text

G A R M O S H K A События интерфейса 05 ∞

Slide 6

Slide 6 text

Таймеры и анимация 06

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Когда один callback — всё здорово!

Slide 9

Slide 9 text

l o g i n ( ' u s e r : p a s s @ s e r v e r ' , f u n c t i o n ( e r r , s e r v e r ) { i f ( e r r ) r e t u r n c b ( e r r ) ; s e r v e r . o p e n ( ' d b ' , f u n c t i o n ( e r r , d b ) { i f ( e r r ) r e t u r n c b ( e r r ) ; d b . q u e r y ( q u e r y , f u n c t i o n ( e r r , v i e w ) { } ) ; } ) ; } ) ; Последовательные запросы 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 09

Slide 10

Slide 10 text

v a r r o w s = [ ] , t o t a l = v i e w . l e n g t h ; f u n c t i o n f e t c h ( e r r , r o w ) { i f ( e r r ) r e t u r n c b ( e r r ) ; i f ( r o w s . l e n g t h = = = t o t a l ) c b ( n u l l , r o w s ) ; } f o r ( v a r i = 0 ; i < t o t a l ; i + + ) { v i e w . g e t ( i , f e t c h ) ; } Параллельные запросы 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 0 8 . 10

Slide 11

Slide 11 text

Шум l o g i n ( ' u s e r : p a s s @ s e r v e r ' , f u n c t i o n ( e r r , s e r v e r ) { i f ( e r r ) r e t u r n c b ( e r r ) ; s e r v e r . o p e n ( ' d b ' , f u n c t i o n ( e r r , d b ) { i f ( e r r ) r e t u r n c b ( e r r ) ; d b . q u e r y ( q u e r y , f u n c t i o n ( e r r , v i e w ) { } ) ; } ) ; } ) ; 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 11

Slide 12

Slide 12 text

● Статус ошибки ● Однообразная обработка ошибки ● Глубина вложенности Шум 12

Slide 13

Slide 13 text

d b . q u e r y ( q u e r y , f u n c t i o n ( e r r , v i e w ) { } ) ; Как отменить или игнорировать запрос в этом случае? d b . q u e r y ( q u e r y , f n ) . a b o r t ( ) ; / / . c a n c e l ( ) ? d b . q u e r y ( q u e r y , f u n c t i o n ( e r r ) { i f ( e r r . m e s s a g e = = = ' a b o r t ' ) r e t u r n ; } ) ; Сложно отменить действие 0 1 . 0 1 . 0 2 . 0 3 . 0 4 . 13

Slide 14

Slide 14 text

q u e r y ( q u e r y 1 , f u n c t i o n ( e r r , v i e w ) { } ) ; q u e r y ( q u e r y 2 , f u n c t i o n ( e r r , v i e w ) { } ) ; q u e r y ( q u e r y 3 , f u n c t i o n ( e r r , v i e w ) { } ) ; 3 запроса — 3 попытки логина. Для кэша нужно еще дописать код. Несколько обработчиков 0 1 . 0 2 . 0 3 . 14

Slide 15

Slide 15 text

f u n c t i o n u b e r Q u e r y G e n e r a t o r ( d a t a ) { / / Г о т о в и м q u e r y F r o m D a t a r e t u r n q u e r y ( q u e r y F r o m D a t a ) ; } f u n c t i o n u b e r Q u e r y G e n e r a t o r ( d a t a , f n ) { q u e r y ( q u e r y F r o m D a t a , f n ) ; } Делегирование результата 0 1 . 0 2 . 0 3 . 0 4 . 0 1 . 0 2 . 0 3 . 15

Slide 16

Slide 16 text

У callback-ов нет единого интерфейса

Slide 17

Slide 17 text

● Последний аргумент ● Свойство конфига или метод – success – complete – done – finish – ??? Нет единого интерфейса 17

Slide 18

Slide 18 text

$ ( ' d i v ' ) . a n i m a t e ( { } , f u n c t i o n ( ) { } ) ; / / А м о ж н о е щ е в о т т а к $ ( ' d i v ' ) . a n i m a t e ( { } , { c o m p l e t e : f u n c t i o n ( ) { } } ) ; Нет единого интерфейса 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 18

Slide 19

Slide 19 text

$ . a j a x ( { u r l : u r l s u c c e s s : f u n c t i o n ( ) { } } ) ; $ . a j a x ( { u r l : u r l } ) . d o n e ( f u n c t i o n ( ) { } ) ; Нет единого интерфейса 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 19

Slide 20

Slide 20 text

Магия

Slide 21

Slide 21 text

● Step.js ● Streamline.js ● Fibers ● ??? Магия 21

Slide 22

Slide 22 text

S t e p ( f u n c t i o n l o g i n ( ) { l o g i n ( ' u s e r : p a s s @ s e r v e r ' , t h i s ) ; } , f u n c t i o n o p e n D a t a b a s e ( e r r , d b ) { i f ( e r r ) t h r o w e r r ; d b . q u e r y ( q u e r y , t h i s ) ; } ) ; Step.js 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 22

Slide 23

Slide 23 text

v a r d b = l o g i n ( ' u s e r : p a s s @ s e r v e r ' , _ ) ; d b . q u e r y ( q u e r y , _ ) ; Вроде бы ничего! Streamline.js 0 1 . 0 2 . 23

Slide 24

Slide 24 text

Streamline.js ( f s t r e a m l i n e _ _ . c r e a t e ( f u n c t i o n ( _ ) { v a r d b = ( y i e l d f s t r e a m l i n e _ _ . i n v o k e ( n u l l , l o g i n , [ ' u s e r : p a s s @ s e r v e r ' , _ ] , 1 ) ) ; ( y i e l d f s t r e a m l i n e _ _ . i n v o k e ( d b , " q u e r y " , [ q u e r y , _ ] , 1 ) ) ; ; y i e l d ; } , 0 ) . c a l l ( t h i s , f u n c t i o n ( e r r ) { i f ( e r r ) t h r o w e r r ; } ) ) ; 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 24

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

● aka Futures ● Распостранен в других языках ● Стандартизирован Promise/A+ ● Стандарт «Покрыт тестами» Promises/A+ Compliance Test Suite ● Готовые абстракции над fs, http, ... Promise 26

Slide 27

Slide 27 text

l o g i n ( ' u s e r : p a s s @ s e r v e r ' ) . t h e n ( f u n c t i o n ( s e r v e r ) { r e t u r n s e r v e r . o p e n ( ' d b ' ) ; } ) . t h e n ( f u n c t i o n ( d b ) { r e t u r n d b . q u e r y ( q u e r y ) ; } ) Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 27

Slide 28

Slide 28 text

. t h e n ( f u n c t i o n ( v i e w ) { r e t u r n f e t c h R o w s ( v i e w ) ; } , f u n c t i o n h a n d l e E r r o r ( e r r ) { c o n s o l e . e r r o r ( e r r ) ; } ) / / . . . Меньше шума, обработка ошибок в одном месте Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 28

Slide 29

Slide 29 text

● Обещание можно сдержать, а можно не выполнять ● Состояние изменяется только 1 раз ● Результат сохраняется ● Цепочка обещаний ● Можно пообещать нескольким Абстракция над обещанными данными 29

Slide 30

Slide 30 text

v a r P r o m i s e = f u n c t i o n ( ) { t h i s . _ v a l u e = n u l l ; t h i s . i s F u l f i l l e d = f a l s e ; / / o k t h i s . i s R e j e c t e d = f a l s e ; / / f a i l t h i s . i s R e s o l v e d = f a l s e ; / / o k | | f a i l / / . . . } ; Реализация Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 30

Slide 31

Slide 31 text

P r o m i s e . p r o t o t y p e = { / / @ r e t u r n { P r o m i s e } t h e n : f u n c t i o n ( o n F u l f i l l e d , o n R e j e c t e d ) { } , f u l f i l l : f u n c t i o n ( d a t a ) { } , r e j e c t : f u n c t i o n ( e r r o r ) { } } ; Реализация Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 31

Slide 32

Slide 32 text

/ / @ p a r a m { N u m b e r } t i m e / / @ r e t u r n { P r o m i s e } f u n c t i o n t i m e o u t ( t i m e ) { v a r p r o m i s e = n e w P r o m i s e ( ) ; s e t T i m e o u t ( p r o m i s e . f u l f i l l , t i m e ) ; r e t u r n p r o m i s e ; } Использование Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 32

Slide 33

Slide 33 text

t i m e o u t ( 1 0 0 0 ) . t h e n ( f u n c t i o n ( ) { c o n s o l e . l o g ( ' f i r s t ' ) ; r e t u r n t i m e o u t ( 1 0 0 0 ) ; } ) . t h e n ( c o n s o l e . l o g . b i n d ( c o n s o l e , ' s e c o n d ! ' ) ) ; Пример timeout 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . Run 33

Slide 34

Slide 34 text

t i m e o u t ( 1 0 0 0 ) . t h e n ( r a n d o m L o g ) . t h e n ( c o n s o l e . l o g . b i n d ( c o n s o l e , ' d o n e ! ' ) ) ; f u n c t i o n r a n d o m L o g ( ) { v a r r n d = M a t h . r a n d o m ( ) ; c o n s o l e . l o g ( r n d ) ; i f ( r n d < 0 . 5 ) r e t u r n t i m e o u t ( 2 0 0 0 ) ; } Пример timeout 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 0 8 . Run 34

Slide 35

Slide 35 text

● Не хак и не магия ● Единый интерфейс всех промисов ● Меньше шума в коде ● Разделение логики на шаги ● ... ● PROFIT! Promise 35

Slide 36

Slide 36 text

Трюки с Promise

Slide 37

Slide 37 text

/ / $ . w h e n - а г р е г а т о р P r o m i s e / / Р е з у л ь т а т н е р а н ь ш е , ч е м ч е р е з 1 с $ . w h e n ( $ . g e t ( ' / ' ) , $ . g e t ( ' / ? ' ) , t i m e o u t ( 1 0 0 0 ) ) . t h e n ( f u n c t i o n ( r e s ) { c o n s o l e . l o g ( r e s [ 0 ] . l e n g t h + r e s [ 1 ] . l e n g t h ) ; } ) ; Склеивание Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . Run 37

Slide 38

Slide 38 text

n e w A t t e m p t ( g e t 4 0 4 , r e p e a t 3 T i m e s ) . t h e n ( o k , e p i c F a i l , p r o g r e s s ) ; f u n c t i o n g e t 4 0 4 ( ) { r e t u r n $ . g e t ( ' / 4 0 4 ' ) ; } f u n c t i o n r e p e a t 3 T i m e s ( e r r , n u m ) { i f ( n u m < 4 ) r e t u r n 1 0 0 0 ; } Повтор Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . 0 8 . Run 38

Slide 39

Slide 39 text

v a r c a c h e ; f u n c t i o n r e q u e s t ( ) { r e t u r n c a c h e ? c a c h e : c a c h e = $ . g e t ( ' / ' ) ; } r e q u e s t ( ) . t h e n ( f u n c t i o n ( h t m l ) { c o n s o l e . l o g ( h t m l . l e n g t h ) ; } ) ; Прозрачный кэш с Promise 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 0 7 . Run 39

Slide 40

Slide 40 text

● Браузер – $.Deferred – $.when, $.ajax, $.get, $.post, ... ● Node.js – Q: q-io – Vow: vow-fs, vow-asker ● DOM Promises! WHATWG Promise Spec Promise уже рядом! 40

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

● Решение проблем асинхронности будущего ● Оператор y i e l d «Ставит выполнение кода на паузу» ● Когда? – Node.js 0.11.x c - - h a r m o n y - g e n e r a t o r s – Браузеры на V8 3.19 c - - h a r m o n y - g e n e r a t o r s – Firefox 2+ (старый синтаксис) ● Можно транслировать в ES5, но лучше это не делать... Generators 42

Slide 43

Slide 43 text

v a r c o = r e q u i r e ( ' c o ' ) ; c o ( f u n c t i o n * ( ) { v a r s e r v e r = y i e l d l o g i n ( ' u s e r : p a s s @ s e r v e r ' ) , d b = y i e l d s e r v e r . o p e n ( ' d b ' ) , v i e w = y i e l d d b . q u e r y ( q u e r y ) ; } ) ; Скоро на экранах ваших IDE Generators 0 1 . 0 2 . 0 3 . 0 4 . 0 5 . 0 6 . 43

Slide 44

Slide 44 text

yield vs then?

Slide 45

Slide 45 text

● Именно «и», а не «VS» ● Используем вместе – Библиотека Q – Библиотека co ● С Generators код еще чище! ● Обработка ошибок с try/catch! Generators и Promise 45

Slide 46

Slide 46 text

● Готов к использованию сегодня! ● Единый интерфейс ● Стандарт Promise/A+ ● Структурирует код ● Меньше шума в коде ● Куча библиотек: Vow, Q, jQuery Используйте Promise! 46

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

Promise — это не больно! Михаил Давыдов JavaScript-разработчик @azproduction 49

Slide 50

Slide 50 text

● Примеры с презентации ● Promises/A+ ● Differences from Promises/A ● Design of Q library (настоятельно рекомендую) ● Iterators & Generators ● A Study on Solving Callbacks with JavaScript Generators ● A Closer Look at Generators Without Promises Почитать 50

Slide 51

Slide 51 text

c l c k . r u / 8 i 9 p r