O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.
Как перестать отлаживать
асинхронный код
и начать жить
Андрей Саломатин
FrontendConf, Москва
21.05.2015
Schlecht!Script
Schlecht!Script
function f1*red(a, b) {…}
f1*red(a, b)
function f2*blue(c) {…}
f2*blue(c)
3
Функции имеют цвет
Schlecht!Script
/* OK! */
function outer*blue() {
inner*blue()
}
4
Синие могут вызывать только
другие синие функции
/* NOT...
Schlecht!Script
/* OK! */
function outer*red() {
inner2*red()
}
5
Красные могут вызывать и
красные и синие функции
/* OK! ...
Писать и вызывать красные
функции больно!
6
Schlecht!Script
7
Красные функции нужно
называть на немецком!
/* Интерпретатор не поймёт */
function authUser*red() {…}
fu...
Schlecht!Script
8
Красные функции нужно
называть на немецком!
/* RICHTIG! */
function benutzerAutorisierung!*rot() {…}
fun...
Как писать на Schlecht!Script?
9
JavaScript
JavaScript
extends
Schlecht!Script
11
Асинхронные функции
это боль
12
JavaScript
• По-другому работают if/else, for, return
• Нет try/catch
• Ломают абстракцию
13
Асинхронные функции это боль
// выполнять последовательно
for (var i = 0; i < 10; i++) {
if (shouldProcess(i)) {
results.push(process(i));
}
}
14
JavaS...
function maybeProcess(i) {
if (i >= 10) { return; }
shouldProcess(function(should) {
if (should) {
process(i, function(res...
JavaScript
• Не работают if/then, for и т.д.
• Нет try/catch
• Ломают абстракцию
16
Асинхронные функции это боль
Асинхронность
в JavaScript
17
Андрей Саломатин
Productive Mobile
MoscowJS
RadioJS
18
@filipovskii
Асинхронность
Множество событий
Единичная операция
20
Асинхронность: два сценария
Контроль
22
Исключения
23
Единый интерфейс
24
25
Контроль
Исключения
Единый интерфейс
• Работа с множеством событий

EventEmitter

Stream
• Работа с асинхронными операциями

Continuation Passing Style

Promis...
• Работа с множеством событий

Async Generators

• Работа с асинхронными операциями

Async/Await



28
ES7
ES6
Работа с множеством
асинхронных
событий
30
31
Работа с множеством асинхронных событий
EventEmitter
Stream
EventEmitter
32
Объект — источник событий
EventEmitter
33
Примеры
Browser: XMLHttpRequest
Node: http.Server
EventEmitter
emitter.addEventListener(eventName, cb);
emitter.removeEventListener(eventName, cb);
34
API
EventEmitter
35
События XMLHttpRequest
progress (n)
load (1)
abort (1)
error (1)
EventEmitter
36
Реализации
Браузер + Node:

EventEmitter3, Tiny Emitter
Node:

Node EventEmitter
37
Работа с множеством асинхронных событий
EventEmitter
Stream
38
EventEmitter
Stream
Работа с множеством асинхронных событий
Поток данных
Stream
39
Stream
40
Примеры
Node: fs.createReadStream(path)
Node: gulp.src(pattern)
Stream
41
Типы потоков
stylus files css files css prefixed files
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dis...
Stream
42
источник преобразование преобразование потребитель
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
...
43
Stream
44
Реализации
Изоморфные:

RxJS, Kefir, Bacon.js
Node:

Node Streams
45
Работа с множеством асинхронных событий
EventEmitter
Stream
46
Контроль
Исключения
Единый интерфейс
EventEmitter, Stream
Работа с
асинхронными операциями
47
48
Работа с асинхронными операциями
Continuation Passing Style
Promises
Coroutines
Continuation Passing Style
49
Примеры
Browser:
navigator.geolocation.getCurrentPosition(cb)
Node:
fs.stat(path, cb)
try {
var user = fetchUser(userId);
var following = fetchFollowingUsers(userId);
var tweets = fetchTweets(following);
hand...
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, foll...
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, foll...
holenBenutzer!*rot(userId, function(err, user) {
if (err) { return handleError*blue(err); }
holenFolgendenBenutzer!*rot(us...
54
Schlecht!Script
55
Работа с асинхронными операциями
Continuation Passing Style
Promises
Coroutines
56
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
Объект — асинхронная
операция
Promises
57
Promise.prototype.then(successCb, errorCb);
58
API
Promises
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
59
Promises
API
Promises
vs
Continuation Passing Style
60
61
Реализации
jQuery.Deffered
Bluebird
RSVP
Q
Promises
62
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
63
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
Coroutines
64
Coroutines
function getUserName(userId) {
var user = getUser(userId);
return user.name;
}
65
Остановите землю!
Функция, которую можно
приостановить и возобновить
позже
66
Coroutines
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
67
Генераторы: шаг 1 из 3
Corouti...
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
68
Coroutines
Генераторы: шаг 1 и...
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
69
Coroutines
Генерато...
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
70
Coroutines
Генерато...
userNamePromise = getUserName(userId);
71
Coroutines
Генераторы: шаг 3 из 3
Использовать генераторы для
асинхронного кода —
это хак
72
Использовать генераторы для
асинхронного кода —
это хак
73
(но я вас не выдам)
74
Реализации
Браузер + Node (используют транспайлер):

co (generators), task.js (generators)
Node (использует транспайлер...
75
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
76
Контроль
Исключения
Единый интерфейс
CPS, Promises, Coroutines
Работа с множеством событий:
EventEmitter
Stream
Работа с асинхронными операциями:
CPS
Promise
Coroutine
77
ES6
ES7
Работа с асинхронными операциями:
Async/Await
Работа с множеством событий:
Async Generators
80
ES7
Работа с асинхронными операциями:
Async/Await
Работа с множеством событий:
Async Generators
81
ES7ES7
Async/Await
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
82
Генерат...
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
83
Async/Await
Async/Await
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
84
Асинхронная функция
Async/Aw...
Асинхронные функции
легализованы в ES7
85
Async/Await
Работа с асинхронными операциями:
Async/Await
Работа с множеством событий:
Async Generators
86
ES7
Работа с асинхронными операциями:
Async/Await
Работа с множеством событий:
Async Generators
87
ES7
Подписка на события
для людей
Async Generators
88
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
89
События DOM
Asy...
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
90
Async Generator...
doDrawPromise = doDraw();
91
Async Generators
События DOM
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
92
WebSo...
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
93
WebSo...
??? = filterWSMessages(ws);
??? = observe(win, 'mousemove');
??? = observe(ws, 'message');
94
Что возвращает Async Generat...
messagesObservable = filterWSMessages(ws);
eventsObservable = observe(win, 'mousemove');
eventsObservable = observe(ws, 'm...
Observables
Streams
aka
Работа с асинхронными операциями:
Async/Await
Работа с множеством событий:
Async Generators
97
ES7
ES6 и ES7:
асинхронные операции
98
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, foll...
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
100
Получить ленту твито...
try {
var user = await fetchUser(userId);
var following = await fetchFollowingUsers(userId);
var tweets = await fetchTweet...
ES6 и ES7:
обработка множества событий
102
var handler = function(ev) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
};
window.addEventListener('mousemove', ha...
Kefir.fromEvent(window, 'mousemove')
.filter(canDraw)
.onValue(function(ev) {
draw(ev.clientX, ev.clientY)
})
.end(); // п...
for (ev on observe(window, 'mousemove')) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
}
105
DOM события: Async Gen...
Как перестать отлаживать
асинхронный
код и начать жить
106
Определите задачу
107
Обдумайте ограничения
108
Используйте лучшие практики
109
Schlecht!Script?
Спасибо!
bit.ly/async-js
Андрей Саломатин
@filipovskii
FrontendConf, Москва
21.05.2015
"Как перестать отлаживать асинхронный код и начать жить", Андрей Саломатин, FrontendConf 2015
"Как перестать отлаживать асинхронный код и начать жить", Андрей Саломатин, FrontendConf 2015
"Как перестать отлаживать асинхронный код и начать жить", Андрей Саломатин, FrontendConf 2015
Próximos SlideShares
Carregando em…5
×

"Как перестать отлаживать асинхронный код и начать жить", Андрей Саломатин, FrontendConf 2015

1.815 visualizações

Publicada em

Слайды доклада "Как перестать отлаживать асинхронный код и начать жить"

Publicada em: Software
  • Seja o primeiro a comentar

"Как перестать отлаживать асинхронный код и начать жить", Андрей Саломатин, FrontendConf 2015

  1. 1. Как перестать отлаживать асинхронный код и начать жить Андрей Саломатин FrontendConf, Москва 21.05.2015
  2. 2. Schlecht!Script
  3. 3. Schlecht!Script function f1*red(a, b) {…} f1*red(a, b) function f2*blue(c) {…} f2*blue(c) 3 Функции имеют цвет
  4. 4. Schlecht!Script /* OK! */ function outer*blue() { inner*blue() } 4 Синие могут вызывать только другие синие функции /* NOT OK! */ function outer*blue() { inner*red() }
  5. 5. Schlecht!Script /* OK! */ function outer*red() { inner2*red() } 5 Красные могут вызывать и красные и синие функции /* OK! */ function outer*red() { inner2*blue() }
  6. 6. Писать и вызывать красные функции больно! 6
  7. 7. Schlecht!Script 7 Красные функции нужно называть на немецком! /* Интерпретатор не поймёт */ function authUser*red() {…} function getName*red() {…}
  8. 8. Schlecht!Script 8 Красные функции нужно называть на немецком! /* RICHTIG! */ function benutzerAutorisierung!*rot() {…} function nameErhalten!*rot() {…}
  9. 9. Как писать на Schlecht!Script? 9
  10. 10. JavaScript
  11. 11. JavaScript extends Schlecht!Script 11
  12. 12. Асинхронные функции это боль 12
  13. 13. JavaScript • По-другому работают if/else, for, return • Нет try/catch • Ломают абстракцию 13 Асинхронные функции это боль
  14. 14. // выполнять последовательно for (var i = 0; i < 10; i++) { if (shouldProcess(i)) { results.push(process(i)); } } 14 JavaScript if/for синхронно
  15. 15. function maybeProcess(i) { if (i >= 10) { return; } shouldProcess(function(should) { if (should) { process(i, function(result) { results.push(result); maybeProcess(i++); }); } maybeProcess(i++); }); } maybeProcess(0); 15 JavaScript if/for асинхронно
  16. 16. JavaScript • Не работают if/then, for и т.д. • Нет try/catch • Ломают абстракцию 16 Асинхронные функции это боль
  17. 17. Асинхронность в JavaScript 17
  18. 18. Андрей Саломатин Productive Mobile MoscowJS RadioJS 18 @filipovskii
  19. 19. Асинхронность
  20. 20. Множество событий Единичная операция 20 Асинхронность: два сценария
  21. 21. Контроль 22
  22. 22. Исключения 23
  23. 23. Единый интерфейс 24
  24. 24. 25 Контроль Исключения Единый интерфейс
  25. 25. • Работа с множеством событий
 EventEmitter
 Stream • Работа с асинхронными операциями
 Continuation Passing Style
 Promises
 Coroutines 27 ES6
  26. 26. • Работа с множеством событий
 Async Generators
 • Работа с асинхронными операциями
 Async/Await
 
 28 ES7
  27. 27. ES6
  28. 28. Работа с множеством асинхронных событий 30
  29. 29. 31 Работа с множеством асинхронных событий EventEmitter Stream
  30. 30. EventEmitter 32 Объект — источник событий
  31. 31. EventEmitter 33 Примеры Browser: XMLHttpRequest Node: http.Server
  32. 32. EventEmitter emitter.addEventListener(eventName, cb); emitter.removeEventListener(eventName, cb); 34 API
  33. 33. EventEmitter 35 События XMLHttpRequest progress (n) load (1) abort (1) error (1)
  34. 34. EventEmitter 36 Реализации Браузер + Node:
 EventEmitter3, Tiny Emitter Node:
 Node EventEmitter
  35. 35. 37 Работа с множеством асинхронных событий EventEmitter Stream
  36. 36. 38 EventEmitter Stream Работа с множеством асинхронных событий
  37. 37. Поток данных Stream 39
  38. 38. Stream 40 Примеры Node: fs.createReadStream(path) Node: gulp.src(pattern)
  39. 39. Stream 41 Типы потоков stylus files css files css prefixed files gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
  40. 40. Stream 42 источник преобразование преобразование потребитель gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist') Типы потоков
  41. 41. 43
  42. 42. Stream 44 Реализации Изоморфные:
 RxJS, Kefir, Bacon.js Node:
 Node Streams
  43. 43. 45 Работа с множеством асинхронных событий EventEmitter Stream
  44. 44. 46 Контроль Исключения Единый интерфейс EventEmitter, Stream
  45. 45. Работа с асинхронными операциями 47
  46. 46. 48 Работа с асинхронными операциями Continuation Passing Style Promises Coroutines
  47. 47. Continuation Passing Style 49 Примеры Browser: navigator.geolocation.getCurrentPosition(cb) Node: fs.stat(path, cb)
  48. 48. try { var user = fetchUser(userId); var following = fetchFollowingUsers(userId); var tweets = fetchTweets(following); handleResult(tweets); } catch (err) { handleError(err); } 50 Continuation Passing Style Получить ленту твитов синхронно Получить ленту твитов асинхронно
  49. 49. fetchUser(userId, function(err, user) { if (err) { return handleError(err); } fetchFollowingUsers(user, function(err, following) { if (err) { return handleError(err); } fetchTweets(following, function(err, tweets) { if (err) { return handleError(err); } handleResult(tweets); }); }); }); 51 Continuation Passing Style Получить ленту твитов асинхронно
  50. 50. fetchUser(userId, function(err, user) { if (err) { return handleError(err); } fetchFollowingUsers(user, function(err, following) { if (err) { return handleError(err); } fetchTweets(following, function(err, tweets) { if (err) { return handleError(err); } 52 Continuation Passing Style Получить ленту твитов асинхронно
  51. 51. holenBenutzer!*rot(userId, function(err, user) { if (err) { return handleError*blue(err); } holenFolgendenBenutzer!*rot(user, function(err, following) { if (err) { return handleError*blue(err); } holenTweets!*rot(following, function(err, tweets) { if (err) { return handleError(err); } 53 Continuation Passing Style Holen Sie sich die Band tweets asynchron!
  52. 52. 54 Schlecht!Script
  53. 53. 55 Работа с асинхронными операциями Continuation Passing Style Promises Coroutines
  54. 54. 56 Continuation Passing Style Promises Coroutines Работа с асинхронными операциями
  55. 55. Объект — асинхронная операция Promises 57
  56. 56. Promise.prototype.then(successCb, errorCb); 58 API Promises
  57. 57. fetchUser(userId) .then(fetchFollowingUsers) .then(fetchTweets) .then(handleResult, handleError); 59 Promises API
  58. 58. Promises vs Continuation Passing Style 60
  59. 59. 61 Реализации jQuery.Deffered Bluebird RSVP Q Promises
  60. 60. 62 Continuation Passing Style Promises Coroutines Работа с асинхронными операциями
  61. 61. 63 Continuation Passing Style Promises Coroutines Работа с асинхронными операциями
  62. 62. Coroutines 64
  63. 63. Coroutines function getUserName(userId) { var user = getUser(userId); return user.name; } 65 Остановите землю!
  64. 64. Функция, которую можно приостановить и возобновить позже 66 Coroutines
  65. 65. function * getUserName (userId) { var user = yield getUser(userId); return user.name; }; 67 Генераторы: шаг 1 из 3 Coroutines
  66. 66. function * getUserName (userId) { var user = yield getUser(userId); return user.name; }; 68 Coroutines Генераторы: шаг 1 из 3
  67. 67. getUserName = co.wrap(function * (userId) { var user = yield getUser(userId); return user.name; }); 69 Coroutines Генераторы: шаг 2 из 3
  68. 68. getUserName = co.wrap(function * (userId) { var user = yield getUser(userId); return user.name; }); 70 Coroutines Генераторы: шаг 2 из 3
  69. 69. userNamePromise = getUserName(userId); 71 Coroutines Генераторы: шаг 3 из 3
  70. 70. Использовать генераторы для асинхронного кода — это хак 72
  71. 71. Использовать генераторы для асинхронного кода — это хак 73 (но я вас не выдам)
  72. 72. 74 Реализации Браузер + Node (используют транспайлер):
 co (generators), task.js (generators) Node (использует транспайлер):
 Fibers Coroutines
  73. 73. 75 Continuation Passing Style Promises Coroutines Работа с асинхронными операциями
  74. 74. 76 Контроль Исключения Единый интерфейс CPS, Promises, Coroutines
  75. 75. Работа с множеством событий: EventEmitter Stream Работа с асинхронными операциями: CPS Promise Coroutine 77 ES6
  76. 76. ES7
  77. 77. Работа с асинхронными операциями: Async/Await Работа с множеством событий: Async Generators 80 ES7
  78. 78. Работа с асинхронными операциями: Async/Await Работа с множеством событий: Async Generators 81 ES7ES7
  79. 79. Async/Await getUserName = co.wrap(function * (userId) { var user = yield getUser(userId); return user.name; }); 82 Генераторы
  80. 80. async function getUserName(userId) { var user = await getUser(userId); return user.name; } 83 Async/Await Async/Await
  81. 81. async function getUserName(userId) { var user = await getUser(userId); return user.name; } 84 Асинхронная функция Async/Await
  82. 82. Асинхронные функции легализованы в ES7 85 Async/Await
  83. 83. Работа с асинхронными операциями: Async/Await Работа с множеством событий: Async Generators 86 ES7
  84. 84. Работа с асинхронными операциями: Async/Await Работа с множеством событий: Async Generators 87 ES7
  85. 85. Подписка на события для людей Async Generators 88
  86. 86. async function doDraw() { for (let ev on observe(win, 'mousemove')) { draw(ev.clientX, ev.clientY); } } 89 События DOM Async Generators
  87. 87. async function doDraw() { for (let ev on observe(win, 'mousemove')) { draw(ev.clientX, ev.clientY); } } 90 Async Generators События DOM
  88. 88. doDrawPromise = doDraw(); 91 Async Generators События DOM
  89. 89. async function *filterWSMessages(ws) { for (let msg on observe(ws, 'message')) { if (isValid(msg)) yield msg; } } 92 WebSocket сообщения Async Generators
  90. 90. async function *filterWSMessages(ws) { for (let msg on observe(ws, 'message')) { if (isValid(msg)) yield msg; } } 93 WebSocket сообщения Async Generators
  91. 91. ??? = filterWSMessages(ws); ??? = observe(win, 'mousemove'); ??? = observe(ws, 'message'); 94 Что возвращает Async Generator? Async Generators
  92. 92. messagesObservable = filterWSMessages(ws); eventsObservable = observe(win, 'mousemove'); eventsObservable = observe(ws, 'message'); 95 Async Generators Что возвращает Async Generator?
  93. 93. Observables Streams aka
  94. 94. Работа с асинхронными операциями: Async/Await Работа с множеством событий: Async Generators 97 ES7
  95. 95. ES6 и ES7: асинхронные операции 98
  96. 96. fetchUser(userId, function(err, user) { if (err) { return handleError(err); } fetchFollowingUsers(user, function(err, following) { if (err) { return handleError(err); } fetchTweets(following, function(err, tweets) { if (err) { return handleError(err); } handleResult(tweets); }); }); }); 99 ES6 и ES7 Получить ленту твитов: CPS
  97. 97. fetchUser(userId) .then(fetchFollowingUsers) .then(fetchTweets) .then(handleResult, handleError); 100 Получить ленту твитов: Promise ES6 и ES7
  98. 98. try { var user = await fetchUser(userId); var following = await fetchFollowingUsers(userId); var tweets = await fetchTweets(following); handleResult(tweets); } catch (err) { handleError(err); } 101 Получить ленту твитов: Async/Await ES6 и ES7
  99. 99. ES6 и ES7: обработка множества событий 102
  100. 100. var handler = function(ev) { if (canDraw(ev)) { draw(ev.clientX, ev.clientY); } }; window.addEventListener('mousemove', handler); window.removeEventListener('mousemove', handler); // позже 103 DOM события: EventEmitter ES6 и ES7
  101. 101. Kefir.fromEvent(window, 'mousemove') .filter(canDraw) .onValue(function(ev) { draw(ev.clientX, ev.clientY) }) .end(); // позже 104 DOM события: Stream ES6 и ES7
  102. 102. for (ev on observe(window, 'mousemove')) { if (canDraw(ev)) { draw(ev.clientX, ev.clientY); } } 105 DOM события: Async Generators ES6 и ES7
  103. 103. Как перестать отлаживать асинхронный код и начать жить 106
  104. 104. Определите задачу 107
  105. 105. Обдумайте ограничения 108
  106. 106. Используйте лучшие практики 109
  107. 107. Schlecht!Script?
  108. 108. Спасибо! bit.ly/async-js Андрей Саломатин @filipovskii FrontendConf, Москва 21.05.2015

×