Владимир Давыдов: «Стратегия интернет-маркетинга для b2b. Системный подход».
FrontTalks: Михаил Давыдов (Яндекс), «Promise – это не больно»
-
Upload
yandex -
Category
Technology
-
view
1.363 -
download
6
description
Transcript of FrontTalks: Михаил Давыдов (Яндекс), «Promise – это не больно»
Promise —это небольно!Михаил Давыдов, JavaScript-разработчик
2013 год, FrontTalks
Асинхронность везде!
Запросы к серверу
04
Данные пользователя
05
События интерфейса
GA
RM
OS
HK
A
06
∞
Таймеры и анимация
07
Когда один callback —всё здорово!
Последовательные запросыlogin('user:pass@server', function (err, server) {
if (err) return cb(err);
server.open('db', function (err, db) {
if (err) return cb(err);
db.query(query, function (err, view) {});
});
});
01.
02.
03.
04.
05.
06.
07.
10
Параллельные запросыvar rows = [], total = view.length;
function fetch(err, row) {
if (err) return cb(err);
if (rows.length === total) cb(null, rows);
}
for (var i = 0; i < total; i++) {
view.get(i, fetch);
}
01.
02.
03.
04.
05.
06.
07.
08.
11
Шумlogin('user:pass@server', function (err, server) {
if (err) return cb(err);
server.open('db', function (err, db) {
if (err) return cb(err);
db.query(query, function (err, view) {});
});
});
01.
02.
03.
04.
05.
06.
07.
12
Шум● Статус ошибки
● Однообразная обработка ошибки
● Глубина вложенности
13
Сложно отменить действиеdb.query(query, function (err, view) {});
Как отменить или игнорировать запрос в этом случае?
db.query(query, fn).abort(); // .cancel() ?
db.query(query, function (err) {
if (err.message === 'abort') return;
});
01.
01.
02.
03.
04.
14
Несколько обработчиковquery(query1, function (err, view) {});
query(query2, function (err, view) {});
query(query3, function (err, view) {});
3 запроса — 3 попытки логина. Для кэша нужно еще дописать код.
01.
02.
03.
15
Делегирование результатаfunction uberQueryGenerator(data) {
// Готовим queryFromData
return query(queryFromData);
}
function uberQueryGenerator(data, fn) {
query(queryFromData, fn);
}
01.
02.
03.
04.
01.
02.
03.
16
У callback-ов нетединого интерфейса
Нет единого интерфейса● Последний аргумент
● Свойство конфига или метод
– success
– complete
– done
– finish
– ???
18
Нет единого интерфейса$('div').animate({}, function () {});
// А можно еще вот так
$('div').animate({}, {
complete: function () {}
});
01.
02.
03.
04.
05.
19
Нет единого интерфейса$.ajax({
url: url
success: function () {}
});
$.ajax({
url: url
}).done(function () {});
01.
02.
03.
04.
05.
06.
07.
20
Магия
Магия● Step.js
● Streamline.js
● Fibers
● ???
22
Step.jsStep(function login() {
login('user:pass@server', this);
}, function openDatabase(err, db) {
if (err) throw err;
db.query(query, this);
});
01.
02.
03.
04.
05.
06.
23
Streamline.jsvar db = login('user:pass@server', _);
db.query(query, _);
Вроде бы ничего!
01.
02.
24
Streamline.js(fstreamline__.create(function(_) {
var db = (yield fstreamline__
.invoke(null, login, ['user:pass@server', _], 1));
(yield fstreamline__.invoke(db, "query", [query, _], 1));
;yield;}, 0).call(this, function(err) {
if (err) throw err;
}));
01.
02.
03.
04.
05.
06.
07.
25
Promise● aka Futures
● Распостранен в других языках
● Стандартизирован Promise/A+
● Стандарт «Покрыт тестами» Promises/A+ Compliance Test Suite
● Готовые абстракции над fs, http, ...
27
Promiselogin('user:pass@server')
.then(function (server) {
return server.open('db');
})
.then(function (db) {
return db.query(query);
})
01.
02.
03.
04.
05.
06.
07.
28
Promise.then(function (view) {
return fetchRows(view);
}, function handleError(err) {
console.error(err);
}) // ...
Меньше шума, обработка ошибок в одном месте
01.
02.
03.
04.
05.
29
Абстракция над обещаннымиданными
● Обещание можно сдержать, а можно не выполнять
● Состояние изменяется только 1 раз
● Результат сохраняется
● Цепочка обещаний
● Можно пообещать нескольким
30
Реализация Promisevar Promise = function () {
this._value = null;
this.isFulfilled = false; // ok
this.isRejected = false; // fail
this.isResolved = false; // ok || fail
// ...
};
01.
02.
03.
04.
05.
06.
07.
31
Реализация PromisePromise.prototype = {
// @return {Promise}
then: function (onFulfilled, onRejected) {},
fulfill: function (data) {},
reject: function (error) {}
};
01.
02.
03.
04.
05.
06.
32
Использование Promise// @param {Number} time
// @return {Promise}
function timeout(time) {
var promise = new Promise();
setTimeout(promise.fulfill, time);
return promise;
}
01.
02.
03.
04.
05.
06.
07.
33
Пример timeouttimeout(1000)
.then(function () {
console.log('first');
return timeout(1000);
})
.then(console.log.bind(console, 'second!'));
01.
02.
03.
04.
05.
06.
Run
34
Пример timeouttimeout(1000)
.then(randomLog)
.then(console.log.bind(console, 'done!'));
function randomLog() {
var rnd = Math.random();
console.log(rnd);
if (rnd < 0.5) return timeout(2000);
}
01.
02.
03.
04.
05.
06.
07.
08.Run
35
Promise● Не хак и не магия
● Единый интерфейс всех промисов
● Меньше шума в коде
● Разделение логики на шаги
● . . .
● PROFIT!
36
Трюки с Promise
Склеивание Promise// $.when - агрегатор Promise
// Результат не раньше, чем через 1с
$.when($.get('/'), $.get('/?'), timeout(1000))
.then(function (res) {
console.log(res[0].length + res[1].length);
});
01.
02.
03.
04.
05.
06.
Run
38
Повтор Promisenew Attempt(get404, repeat3Times)
.then(ok, epicFail, progress);
function get404() {
return $.get('/404');
}
function repeat3Times(err, num) {
if (num < 4) return 1000;
}
01.
02.
03.
04.
05.
06.
07.
08.Run
39
Прозрачный кэш с Promisevar cache;
function request() {
return cache ? cache : cache = $.get('/');
}
request().then(function (html) {
console.log(html.length);
});
01.
02.
03.
04.
05.
06.
07.Run
40
Promise уже рядом!● Браузер
– $.Deferred
– $.when, $.ajax, $.get, $.post, ...
● Node.js
– Q: q-io
– Vow: vow-fs, vow-asker
● DOM Promises! WHATWG Promise Spec
41
Generators● Решение проблем асинхронности будущего
● Оператор yield «Ставит выполнение кода на паузу»
● Когда?
– Node.js 0.11.x c --harmony-generators
– Браузеры на V8 3.19 c --harmony-generators
– Firefox 2+ (старый синтаксис)
● Можно транслировать в ES5, но лучше это не делать...
43
Generatorsvar co = require('co');
co(function *() {
var server = yield login('user:pass@server'),
db = yield server.open('db'),
view = yield db.query(query);
});
Скоро на экранах ваших IDE
01.
02.
03.
04.
05.
06.
44
yield vs then?
Generators и Promise● Именно «и», а не «VS»
● Используем вместе
– Библиотека Q
– Библиотека co
● С Generators код еще чище!
● Обработка ошибок с try/catch!
46
Используйте Promise!● Готов к использованию сегодня!
● Единый интерфейс
● Стандарт Promise/A+
● Структурирует код
● Меньше шума в коде
● Куча библиотек: Vow, Q, jQuery
47
Promise — это не больно!
Михаил Давыдов
JavaScript-разработчик
@azproduction
50
Почитать● Примеры с презентации
● 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
51
clck.ru/8i9pr