SlideShare a Scribd company logo
Asynchronous Programming
with JavaScript and Node.js
Timur Shemsedinov
Software Architect at Metarhia, Lecturer at KPI
Metarhia
Asynchronous programming in JavaScript as of today
● callbacks
● async.js
● promises
● async/await
● ?
Asynchronous programming in JavaScript as of today
● callbacks
● async.js
● promises
● async/await
● generators/yield
● events
● functor + chaining + composition
Asynchronous programming in JavaScript as of today
● callbacks > async.js
● promises > async/await
● events
● functor + chaining + composition
Callbacks
(callback) => callback(data)
(...args, callback) => callback(err, data)
Use contracts: callback-last, error-first
You can implement hell easely
Callbacks
readConfig('myConfig', (e, data) => {
query('select * from cities', (e, data) => {
httpGet('http://kpi.ua', (e, data) => {
readFile('README.md', (e, data) => {
});
});
});
});
Callbacks
readConfig('myConfig',
query.bind(null, 'select * from cities',
httpGet.bind(null, 'http://kpi.ua',
readFile.bind('README.md', () => {
});
});
});
});
Callbacks
readConfig('myConfig');
function readConfig(fileName) {
...; query('select * from cities');
}
function query(statement) {
...; httpGet('http://kpi.ua');
}
...
Library async.js or analogues
async.method(
[... (data, cb) => cb(err, result) ...],
(err, result) => {}
);
Use callback-last, error-first
Define functions separately, descriptive names
Hell remains
Events
const ee = new EventEmitter();
const f1 = () => ee.emit('step2');
const f2 = () => ee.emit('step3');
const f3 = () => ee.emit('done');
ee.on('step1', f1.bind(null, par));
ee.on('step2', f2.bind(null, par));
ee.on('step3', f3.bind(null, par));
ee.on('done', () => console.log('done'));
ee.emit('step1');
Promise
new Promise((resolve, reject) => {
resolve(data);
reject(new Error(...));
})
.then(result => {}, reason => {})
.catch(err => {});
Separated control flow for success and fail
Hell remains for complex parallel/sequential code
Promise Sequential
Promise.resolve()
.then(readConfig.bind(null, 'myConfig'))
.then(query.bind(null, 'select * from cities'))
.then(httpGet.bind(null, 'http://kpi.ua'))
.catch((err) => console.log(err.message))
.then(readFile.bind(null, 'README.md'))
.catch((err) => console.log(err.message))
.then((data) => {
console.dir({ data });
});
Promise Parallel
Promise.all([
readConfig('myConfig'),
doQuery('select * from cities'),
httpGet('http://kpi.ua'),
readFile('README.md')
]).then((data) => {
console.log('Done');
console.dir({ data });
});
Promise Mixed: parallel / sequential
Promise.resolve()
.then(readConfig.bind(null, 'myConfig'))
.then(() => Promise.all([
query('select * from cities'),
gttpGet('http://kpi.ua')
]))
.then(readFile.bind(null, 'README.md'))
.then((data) => {
console.log('Done');
console.dir({ data });
});
async/await
async function f() {
return await new Promise(...);
}
f().then(console.log).catch(console.error);
Promises under the hood, Control-flow separated
Hell remains, Performance reduced
Functor + Chaining + composition
const c1 = chain()
.do(readConfig, 'myConfig')
.do(doQuery, 'select * from cities')
.do(httpGet, 'http://kpi.ua')
.do(readFile, 'README.md');
c1();
Functor + chaining + composition
function chain(prev = null) {
const cur = () => {
if (cur.prev) {
cur.prev.next = cur;
cur.prev();
} else {
cur.forward();
}
};
cur.prev = prev;
cur.fn = null;
cur.args = null;
...
...
cur.do = (fn, ...args) => {
cur.fn = fn;
cur.args = args;
return chain(cur);
};
cur.forward = () => {
if (cur.fn) cur.fn(cur.args, () => {
if (cur.next) cur.next.forward();
});
};
return cur;
}
Problems
of callbacks, async.js, Promise, async/await
● Nesting and syntax
● Different contracts
● Not cancellable, no timeouts
● Complexity and Performance
Tricks
Add timeout to any function
const fn = (par) => {
console.log('Function called, par: ' + par);
};
const fn100 = timeout(100, fn);
const fn200 = timeout(200, fn);
setTimeout(() => {
fn100('first'); fn200('second');
}, 150);
Add timeout to any function
function timeout(msec, fn) {
let timer = setTimeout(() => {
if (timer) console.log('Function timedout');
timer = null;
}, msec);
return (...args) => {
if (timer) {
timer = null;
fn(...args);
}
};
}
Make function cancelable
const fn = (par) => {
console.log('Function called, par: ' + par);
};
const f = cancelable(fn);
f('first');
f.cancel();
f('second');
Make function cancelable
const cancelable = (fn) => {
const wrapper = (...args) => {
if (fn) return fn(...args);
};
wrapper.cancel = () => {
fn = null;
};
return wrapper;
};
More wrappers
const f1 = timeout(1000, fn);
const f2 = cancelable(fn);
const f3 = once(fn);
const f4 = limit(10, fn);
const f5 = throttle(10, 1000, fn);
const f6 = debounce(1000, fn);
const f7 = utils(fn)
.limit(10)
.throttle(10, 100)
.timeout(1000);
Promisify and Callbackify
const promise = promisify(asyncFunction);
promise.then(...).catch(...);
const callback = callbackify(promise);
callback((err, value) => { ... });
Sync function to async
const f1 = par => par; const f2 = par => par;
const f3 = par => par; const f4 = par => par;
console.log(f4(f3(f2(f1('value')))));
const af1 = toAsync(f1); const af2 = toAsync(f2);
const af3 = toAsync(f3); const af4 = toAsync(f4);
af1('value', (e, data) => {
af2(data, (e, data) => {
af3(data, (e, data) => {
af4(data, (e, data) => {
console.log(data);
});
});
});
});
Sync function to async
const last = arr => arr[arr.length - 1];
const toAsync = fn => (...args) => {
const callback = last(args);
args.pop();
callback(null, fn(...args));
};
Sync function to Promise
const f1 = par => par; const f2 = par => par;
const f3 = par => par; const f4 = par => par;
console.log(f4(f3(f2(f1('value')))));
const pf1 = toPromise(f1); const pf2 = toPromise(f2);
const pf3 = toPromise(f3); const pf4 = toPromise(f4);
Promise.resolve()
.then(pf1.bind(null, 'value'))
.then(pf2())
.then(pf3())
.then(pf4())
.then((data) => {
console.log(data);
});
Sync function to Promise
const toPromise = fn => (...args) =>
new Promise(resolve => resolve(fn(...args)));
Convertors
● err-back to Promise
● Promise to err-back
● sync function to Promise
● sync function to err-back
● Events to Promise
● Promise to Events
● Events to err-back
● err-back to Events
Metasync
Metasync
● Function composition for asynchronous I/O
● Specific asynchronous abstractions
● Short and expressive syntax
● We use errback compatible contract
● IH
Function composition
inc = a => ++a;
square = a => a * a;
lg = x => log(10, x);
f = compose(inc, square, lg);
...but it’s synchronous
Function composition
Function composition is a great idea for asynchronous I/O
But there are questions:
● What about contracts?
○ for calls and callbacks, arguments and errors
○ timeouts, queueing, throttling
● How to add asynchronicity?
○ parallel and sequential
Asynchronous function composition
const readCfg = (name, cb) => fs.readFile(name, cb);
const netReq = (data, cb) => http.get(data.url, cb);
const dbReq = (query, cb) => db.select(query, cb);
const f1 = sequential(readCfg, netReq, dbReq);
const f2 = parallel(dbReq1, dbReq2, dbReq3);
// f1 & f2 contracts (...args, cb) => cb(err, data)
Flow commutation like in electronics
const fx = metasync.flow(
[f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]
);
Data collector
const dc1 = new metasync.DataCollector(4);
const dc2 = new metasync.DataCollector(4, 5000);
dc1.on('error', (err, key) => {});
dc2.on('timeout', (err, data) => {});
dc2.on('done', (errs, data) => {});
dc1.collect(data);
Key collector
const keyCollector = new KeyCollector(
['k1', 'k2'], (data) => console.dir(data)
);
keyCollector.collect('k1', {});
fs.readFile('HISTORY.md', (err, data) => {
keyCollector.collect('history', data);
});
Key collector
const kc = new metasync.KeyCollector(
['user', 'config', 'readme', 'timer'], (data) => console.dir(data)
);
kc.collect('user', { name: 'Marcus Aurelius' });
fs.readFile('HISTORY.md', (err,data) => kc.collect('history', data));
fs.readFile('README.md', (err,data) => kc.collect('readme', data));
setTimeout(
() => keyCollector.collect('timer', { date: new Date() }),
ASYNC_TIMEOUT
);
Collector
const dc1 = metasync
.collect(3)
.timeout(5000)
.done((err, data) => {});
dc1(item);
const dc2 = metasync
.collect(['key1', 'key2', 'key3'])
.timeout(5000)
.done((err, data) => {});
dc2(key, value);
Collector features
const dc = metasync
.collect(count)
.distinct()
.done((err, data) => {});
dc(key, error, value);
dc.pick(key, value);
dc.fail(key, error);
fs.readFile(filename, dc.bind(null, key));
dc.take(key, fs.readFile, filename);
Asynchronous programming with java script and node.js
Throttle
const t1 = metasync.throttle(5000, f);
t1();
t1();
t1(); // single call
setTimeout(t1, 7000); // another call
setTimeout(t1, 7100);
// will be fired at about 7000+5000
Queue
const cq = metasync.queue(3)
.wait(2000)
.timeout(5000)
.throttle(100, 1000)
.process((item, cb) => cb(err, result))
.success((item) => {})
.failure((item) => {})
.done(() => {})
.drain(() => {});
Timur Shemsedinov
tshemsedinov@github, timur.shemsedinov@gmail.com
tshemsedinov@facebook, marcusaurelius@habrahabr
Github repo: github.com/metarhia/metasync
http://how.programming.works
Telegram: t.me/metarhia & t.me/nodeua
Metarhia meetups: meetup.com/NodeUA,
meetup.com/HowProgrammingWorks
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.js
Metarhia

More Related Content

PDF
Asynchronous programming and mutlithreading
Timur Shemsedinov
 
PDF
How are Race Conditions in single threaded JavaScript possible?
Timur Shemsedinov
 
PDF
Node.js in 2020 - part 3
Timur Shemsedinov
 
PDF
Patterns and antipatterns
Timur Shemsedinov
 
PDF
Node.js middleware: Never again!
Timur Shemsedinov
 
PDF
Metarhia KievJS 22-Feb-2018
Timur Shemsedinov
 
PDF
Race-conditions-web-locks-and-shared-memory
Timur Shemsedinov
 
PDF
Node.js in 2020 - part 1
Timur Shemsedinov
 
Asynchronous programming and mutlithreading
Timur Shemsedinov
 
How are Race Conditions in single threaded JavaScript possible?
Timur Shemsedinov
 
Node.js in 2020 - part 3
Timur Shemsedinov
 
Patterns and antipatterns
Timur Shemsedinov
 
Node.js middleware: Never again!
Timur Shemsedinov
 
Metarhia KievJS 22-Feb-2018
Timur Shemsedinov
 
Race-conditions-web-locks-and-shared-memory
Timur Shemsedinov
 
Node.js in 2020 - part 1
Timur Shemsedinov
 

What's hot (20)

PDF
Node.js in 2020
Timur Shemsedinov
 
PDF
Node.js in 2020 - part 2
Timur Shemsedinov
 
PDF
Новое в JavaScript: ES.Next, ECMAScript 2020, ES11, ES10, ES9, ES8, ES7, ES6,...
Timur Shemsedinov
 
PDF
Web Locks API
Timur Shemsedinov
 
PDF
Private cloud without vendor lock // Serverless
Timur Shemsedinov
 
PDF
JavaScript в браузере: Web API (часть 1)
Timur Shemsedinov
 
PDF
Programming Languages: comparison, history, future
Timur Shemsedinov
 
PDF
Serverless Clouds (FaaS) and request context isolation in Node.js
Timur Shemsedinov
 
PDF
Введение в SQL
Timur Shemsedinov
 
PDF
Prototype programming in JavaScript
Timur Shemsedinov
 
PDF
How to keep control and safety in the clouds
Timur Shemsedinov
 
PDF
JS Fest 2019 Node.js Antipatterns
Timur Shemsedinov
 
PDF
Bytes in the Machine: Inside the CPython interpreter
akaptur
 
PDF
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
akaptur
 
PDF
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
akaptur
 
PDF
Python opcodes
alexgolec
 
PDF
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
akaptur
 
PDF
JavaScript - Agora nervoso
Luis Vendrame
 
PDF
Diving into byte code optimization in python
Chetan Giridhar
 
PPTX
TCO in Python via bytecode manipulation.
lnikolaeva
 
Node.js in 2020
Timur Shemsedinov
 
Node.js in 2020 - part 2
Timur Shemsedinov
 
Новое в JavaScript: ES.Next, ECMAScript 2020, ES11, ES10, ES9, ES8, ES7, ES6,...
Timur Shemsedinov
 
Web Locks API
Timur Shemsedinov
 
Private cloud without vendor lock // Serverless
Timur Shemsedinov
 
JavaScript в браузере: Web API (часть 1)
Timur Shemsedinov
 
Programming Languages: comparison, history, future
Timur Shemsedinov
 
Serverless Clouds (FaaS) and request context isolation in Node.js
Timur Shemsedinov
 
Введение в SQL
Timur Shemsedinov
 
Prototype programming in JavaScript
Timur Shemsedinov
 
How to keep control and safety in the clouds
Timur Shemsedinov
 
JS Fest 2019 Node.js Antipatterns
Timur Shemsedinov
 
Bytes in the Machine: Inside the CPython interpreter
akaptur
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
akaptur
 
"A 1,500 line (!!) switch statement powers your Python!" - Allison Kaptur, !!...
akaptur
 
Python opcodes
alexgolec
 
Allison Kaptur: Bytes in the Machine: Inside the CPython interpreter, PyGotha...
akaptur
 
JavaScript - Agora nervoso
Luis Vendrame
 
Diving into byte code optimization in python
Chetan Giridhar
 
TCO in Python via bytecode manipulation.
lnikolaeva
 
Ad

Similar to Asynchronous programming with java script and node.js (20)

PDF
Timur Shemsedinov "Пишу на колбеках, а что... (Асинхронное программирование)"
OdessaJS Conf
 
PDF
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
PDF
Asynchronous programming done right - Node.js
Piotr Pelczar
 
PPTX
Avoiding Callback Hell with Async.js
cacois
 
PDF
Job Queue in Golang
Bo-Yi Wu
 
PDF
All you need to know about Callbacks, Promises, Generators
Brainhub
 
PPTX
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software
 
PDF
用 Go 語言打造多台機器 Scale 架構
Bo-Yi Wu
 
PPTX
EcmaScript unchained
Eduard Tomàs
 
PDF
How to practice functional programming in react
Netta Bondy
 
KEY
Node.js - Best practices
Felix Geisendörfer
 
PDF
Alexey Tsoy Meta Programming in C++ 16.11.17
LogeekNightUkraine
 
PPTX
Academy PRO: ES2015
Binary Studio
 
PDF
Rntb20200805
t k
 
PDF
Rxjs vienna
Christoffer Noring
 
PDF
オープンデータを使ったモバイルアプリ開発(応用編)
Takayuki Goto
 
PDF
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
PDF
ES6 - Next Generation Javascript
RameshNair6
 
PDF
Coding in Style
scalaconfjp
 
PDF
Refactoring to Macros with Clojure
Dmitry Buzdin
 
Timur Shemsedinov "Пишу на колбеках, а что... (Асинхронное программирование)"
OdessaJS Conf
 
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
Asynchronous programming done right - Node.js
Piotr Pelczar
 
Avoiding Callback Hell with Async.js
cacois
 
Job Queue in Golang
Bo-Yi Wu
 
All you need to know about Callbacks, Promises, Generators
Brainhub
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software
 
用 Go 語言打造多台機器 Scale 架構
Bo-Yi Wu
 
EcmaScript unchained
Eduard Tomàs
 
How to practice functional programming in react
Netta Bondy
 
Node.js - Best practices
Felix Geisendörfer
 
Alexey Tsoy Meta Programming in C++ 16.11.17
LogeekNightUkraine
 
Academy PRO: ES2015
Binary Studio
 
Rntb20200805
t k
 
Rxjs vienna
Christoffer Noring
 
オープンデータを使ったモバイルアプリ開発(応用編)
Takayuki Goto
 
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
ES6 - Next Generation Javascript
RameshNair6
 
Coding in Style
scalaconfjp
 
Refactoring to Macros with Clojure
Dmitry Buzdin
 
Ad

More from Timur Shemsedinov (15)

PDF
How to use Chat GPT in JavaScript optimizations for Node.js
Timur Shemsedinov
 
PDF
IT Revolution in 2023-2024: AI, GPT, business transformation, future professi...
Timur Shemsedinov
 
PDF
Multithreading in Node.js and JavaScript
Timur Shemsedinov
 
PDF
Node.js threads for I/O-bound tasks
Timur Shemsedinov
 
PDF
Node.js Меньше сложности, больше надежности Holy.js 2021
Timur Shemsedinov
 
PDF
Rethinking low-code
Timur Shemsedinov
 
PDF
Hat full of developers
Timur Shemsedinov
 
PDF
FwDays 2021: Metarhia Technology Stack for Node.js
Timur Shemsedinov
 
PDF
Node.js for enterprise - JS Conference
Timur Shemsedinov
 
PDF
Node.js for enterprise 2021 - JavaScript Fwdays 3
Timur Shemsedinov
 
PDF
Node.js in 2021
Timur Shemsedinov
 
PDF
Information system structure and architecture
Timur Shemsedinov
 
PDF
Базы данных в 2020
Timur Shemsedinov
 
PDF
Почему хорошее ИТ-образование невостребовано рыночком
Timur Shemsedinov
 
PDF
Node.js security
Timur Shemsedinov
 
How to use Chat GPT in JavaScript optimizations for Node.js
Timur Shemsedinov
 
IT Revolution in 2023-2024: AI, GPT, business transformation, future professi...
Timur Shemsedinov
 
Multithreading in Node.js and JavaScript
Timur Shemsedinov
 
Node.js threads for I/O-bound tasks
Timur Shemsedinov
 
Node.js Меньше сложности, больше надежности Holy.js 2021
Timur Shemsedinov
 
Rethinking low-code
Timur Shemsedinov
 
Hat full of developers
Timur Shemsedinov
 
FwDays 2021: Metarhia Technology Stack for Node.js
Timur Shemsedinov
 
Node.js for enterprise - JS Conference
Timur Shemsedinov
 
Node.js for enterprise 2021 - JavaScript Fwdays 3
Timur Shemsedinov
 
Node.js in 2021
Timur Shemsedinov
 
Information system structure and architecture
Timur Shemsedinov
 
Базы данных в 2020
Timur Shemsedinov
 
Почему хорошее ИТ-образование невостребовано рыночком
Timur Shemsedinov
 
Node.js security
Timur Shemsedinov
 

Recently uploaded (20)

PDF
Jenkins: An open-source automation server powering CI/CD Automation
SaikatBasu37
 
PDF
lesson-2-rules-of-netiquette.pdf.bshhsjdj
jasmenrojas249
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PDF
Protecting the Digital World Cyber Securit
dnthakkar16
 
PPTX
Role Of Python In Programing Language.pptx
jaykoshti048
 
PDF
Exploring AI Agents in Process Industries
amoreira6
 
PDF
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
PPTX
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
PPTX
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
PDF
Bandai Playdia The Book - David Glotz
BluePanther6
 
PDF
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
PDF
Community & News Update Q2 Meet Up 2025
VictoriaMetrics
 
PDF
Micromaid: A simple Mermaid-like chart generator for Pharo
ESUG
 
PPTX
Presentation about variables and constant.pptx
kr2589474
 
PPTX
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
PDF
Solar Panel Installation Guide – Step By Step Process 2025.pdf
CRMLeaf
 
PDF
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
PDF
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
PDF
On Software Engineers' Productivity - Beyond Misleading Metrics
Romén Rodríguez-Gil
 
PPTX
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
Jenkins: An open-source automation server powering CI/CD Automation
SaikatBasu37
 
lesson-2-rules-of-netiquette.pdf.bshhsjdj
jasmenrojas249
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
Protecting the Digital World Cyber Securit
dnthakkar16
 
Role Of Python In Programing Language.pptx
jaykoshti048
 
Exploring AI Agents in Process Industries
amoreira6
 
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
Bandai Playdia The Book - David Glotz
BluePanther6
 
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
Community & News Update Q2 Meet Up 2025
VictoriaMetrics
 
Micromaid: A simple Mermaid-like chart generator for Pharo
ESUG
 
Presentation about variables and constant.pptx
kr2589474
 
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
Solar Panel Installation Guide – Step By Step Process 2025.pdf
CRMLeaf
 
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
On Software Engineers' Productivity - Beyond Misleading Metrics
Romén Rodríguez-Gil
 
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 

Asynchronous programming with java script and node.js

  • 1. Asynchronous Programming with JavaScript and Node.js Timur Shemsedinov Software Architect at Metarhia, Lecturer at KPI
  • 3. Asynchronous programming in JavaScript as of today ● callbacks ● async.js ● promises ● async/await ● ?
  • 4. Asynchronous programming in JavaScript as of today ● callbacks ● async.js ● promises ● async/await ● generators/yield ● events ● functor + chaining + composition
  • 5. Asynchronous programming in JavaScript as of today ● callbacks > async.js ● promises > async/await ● events ● functor + chaining + composition
  • 6. Callbacks (callback) => callback(data) (...args, callback) => callback(err, data) Use contracts: callback-last, error-first You can implement hell easely
  • 7. Callbacks readConfig('myConfig', (e, data) => { query('select * from cities', (e, data) => { httpGet('http://kpi.ua', (e, data) => { readFile('README.md', (e, data) => { }); }); }); });
  • 8. Callbacks readConfig('myConfig', query.bind(null, 'select * from cities', httpGet.bind(null, 'http://kpi.ua', readFile.bind('README.md', () => { }); }); }); });
  • 9. Callbacks readConfig('myConfig'); function readConfig(fileName) { ...; query('select * from cities'); } function query(statement) { ...; httpGet('http://kpi.ua'); } ...
  • 10. Library async.js or analogues async.method( [... (data, cb) => cb(err, result) ...], (err, result) => {} ); Use callback-last, error-first Define functions separately, descriptive names Hell remains
  • 11. Events const ee = new EventEmitter(); const f1 = () => ee.emit('step2'); const f2 = () => ee.emit('step3'); const f3 = () => ee.emit('done'); ee.on('step1', f1.bind(null, par)); ee.on('step2', f2.bind(null, par)); ee.on('step3', f3.bind(null, par)); ee.on('done', () => console.log('done')); ee.emit('step1');
  • 12. Promise new Promise((resolve, reject) => { resolve(data); reject(new Error(...)); }) .then(result => {}, reason => {}) .catch(err => {}); Separated control flow for success and fail Hell remains for complex parallel/sequential code
  • 13. Promise Sequential Promise.resolve() .then(readConfig.bind(null, 'myConfig')) .then(query.bind(null, 'select * from cities')) .then(httpGet.bind(null, 'http://kpi.ua')) .catch((err) => console.log(err.message)) .then(readFile.bind(null, 'README.md')) .catch((err) => console.log(err.message)) .then((data) => { console.dir({ data }); });
  • 14. Promise Parallel Promise.all([ readConfig('myConfig'), doQuery('select * from cities'), httpGet('http://kpi.ua'), readFile('README.md') ]).then((data) => { console.log('Done'); console.dir({ data }); });
  • 15. Promise Mixed: parallel / sequential Promise.resolve() .then(readConfig.bind(null, 'myConfig')) .then(() => Promise.all([ query('select * from cities'), gttpGet('http://kpi.ua') ])) .then(readFile.bind(null, 'README.md')) .then((data) => { console.log('Done'); console.dir({ data }); });
  • 16. async/await async function f() { return await new Promise(...); } f().then(console.log).catch(console.error); Promises under the hood, Control-flow separated Hell remains, Performance reduced
  • 17. Functor + Chaining + composition const c1 = chain() .do(readConfig, 'myConfig') .do(doQuery, 'select * from cities') .do(httpGet, 'http://kpi.ua') .do(readFile, 'README.md'); c1();
  • 18. Functor + chaining + composition function chain(prev = null) { const cur = () => { if (cur.prev) { cur.prev.next = cur; cur.prev(); } else { cur.forward(); } }; cur.prev = prev; cur.fn = null; cur.args = null; ... ... cur.do = (fn, ...args) => { cur.fn = fn; cur.args = args; return chain(cur); }; cur.forward = () => { if (cur.fn) cur.fn(cur.args, () => { if (cur.next) cur.next.forward(); }); }; return cur; }
  • 19. Problems of callbacks, async.js, Promise, async/await ● Nesting and syntax ● Different contracts ● Not cancellable, no timeouts ● Complexity and Performance
  • 21. Add timeout to any function const fn = (par) => { console.log('Function called, par: ' + par); }; const fn100 = timeout(100, fn); const fn200 = timeout(200, fn); setTimeout(() => { fn100('first'); fn200('second'); }, 150);
  • 22. Add timeout to any function function timeout(msec, fn) { let timer = setTimeout(() => { if (timer) console.log('Function timedout'); timer = null; }, msec); return (...args) => { if (timer) { timer = null; fn(...args); } }; }
  • 23. Make function cancelable const fn = (par) => { console.log('Function called, par: ' + par); }; const f = cancelable(fn); f('first'); f.cancel(); f('second');
  • 24. Make function cancelable const cancelable = (fn) => { const wrapper = (...args) => { if (fn) return fn(...args); }; wrapper.cancel = () => { fn = null; }; return wrapper; };
  • 25. More wrappers const f1 = timeout(1000, fn); const f2 = cancelable(fn); const f3 = once(fn); const f4 = limit(10, fn); const f5 = throttle(10, 1000, fn); const f6 = debounce(1000, fn); const f7 = utils(fn) .limit(10) .throttle(10, 100) .timeout(1000);
  • 26. Promisify and Callbackify const promise = promisify(asyncFunction); promise.then(...).catch(...); const callback = callbackify(promise); callback((err, value) => { ... });
  • 27. Sync function to async const f1 = par => par; const f2 = par => par; const f3 = par => par; const f4 = par => par; console.log(f4(f3(f2(f1('value'))))); const af1 = toAsync(f1); const af2 = toAsync(f2); const af3 = toAsync(f3); const af4 = toAsync(f4); af1('value', (e, data) => { af2(data, (e, data) => { af3(data, (e, data) => { af4(data, (e, data) => { console.log(data); }); }); }); });
  • 28. Sync function to async const last = arr => arr[arr.length - 1]; const toAsync = fn => (...args) => { const callback = last(args); args.pop(); callback(null, fn(...args)); };
  • 29. Sync function to Promise const f1 = par => par; const f2 = par => par; const f3 = par => par; const f4 = par => par; console.log(f4(f3(f2(f1('value'))))); const pf1 = toPromise(f1); const pf2 = toPromise(f2); const pf3 = toPromise(f3); const pf4 = toPromise(f4); Promise.resolve() .then(pf1.bind(null, 'value')) .then(pf2()) .then(pf3()) .then(pf4()) .then((data) => { console.log(data); });
  • 30. Sync function to Promise const toPromise = fn => (...args) => new Promise(resolve => resolve(fn(...args)));
  • 31. Convertors ● err-back to Promise ● Promise to err-back ● sync function to Promise ● sync function to err-back ● Events to Promise ● Promise to Events ● Events to err-back ● err-back to Events
  • 33. Metasync ● Function composition for asynchronous I/O ● Specific asynchronous abstractions ● Short and expressive syntax ● We use errback compatible contract ● IH
  • 34. Function composition inc = a => ++a; square = a => a * a; lg = x => log(10, x); f = compose(inc, square, lg); ...but it’s synchronous
  • 35. Function composition Function composition is a great idea for asynchronous I/O But there are questions: ● What about contracts? ○ for calls and callbacks, arguments and errors ○ timeouts, queueing, throttling ● How to add asynchronicity? ○ parallel and sequential
  • 36. Asynchronous function composition const readCfg = (name, cb) => fs.readFile(name, cb); const netReq = (data, cb) => http.get(data.url, cb); const dbReq = (query, cb) => db.select(query, cb); const f1 = sequential(readCfg, netReq, dbReq); const f2 = parallel(dbReq1, dbReq2, dbReq3); // f1 & f2 contracts (...args, cb) => cb(err, data)
  • 37. Flow commutation like in electronics const fx = metasync.flow( [f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9] );
  • 38. Data collector const dc1 = new metasync.DataCollector(4); const dc2 = new metasync.DataCollector(4, 5000); dc1.on('error', (err, key) => {}); dc2.on('timeout', (err, data) => {}); dc2.on('done', (errs, data) => {}); dc1.collect(data);
  • 39. Key collector const keyCollector = new KeyCollector( ['k1', 'k2'], (data) => console.dir(data) ); keyCollector.collect('k1', {}); fs.readFile('HISTORY.md', (err, data) => { keyCollector.collect('history', data); });
  • 40. Key collector const kc = new metasync.KeyCollector( ['user', 'config', 'readme', 'timer'], (data) => console.dir(data) ); kc.collect('user', { name: 'Marcus Aurelius' }); fs.readFile('HISTORY.md', (err,data) => kc.collect('history', data)); fs.readFile('README.md', (err,data) => kc.collect('readme', data)); setTimeout( () => keyCollector.collect('timer', { date: new Date() }), ASYNC_TIMEOUT );
  • 41. Collector const dc1 = metasync .collect(3) .timeout(5000) .done((err, data) => {}); dc1(item); const dc2 = metasync .collect(['key1', 'key2', 'key3']) .timeout(5000) .done((err, data) => {}); dc2(key, value);
  • 42. Collector features const dc = metasync .collect(count) .distinct() .done((err, data) => {}); dc(key, error, value); dc.pick(key, value); dc.fail(key, error); fs.readFile(filename, dc.bind(null, key)); dc.take(key, fs.readFile, filename);
  • 44. Throttle const t1 = metasync.throttle(5000, f); t1(); t1(); t1(); // single call setTimeout(t1, 7000); // another call setTimeout(t1, 7100); // will be fired at about 7000+5000
  • 45. Queue const cq = metasync.queue(3) .wait(2000) .timeout(5000) .throttle(100, 1000) .process((item, cb) => cb(err, result)) .success((item) => {}) .failure((item) => {}) .done(() => {}) .drain(() => {});
  • 46. Timur Shemsedinov tshemsedinov@github, [email protected] tshemsedinov@facebook, marcusaurelius@habrahabr Github repo: github.com/metarhia/metasync http://how.programming.works Telegram: t.me/metarhia & t.me/nodeua Metarhia meetups: meetup.com/NodeUA, meetup.com/HowProgrammingWorks