Zhigalov Sergey, Yandex
Zhigalov Sergey
Frontend Union Conf, 2015
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
Get list of airlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
Get flight cost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = Sort airlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
Get list of airlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
Get flight cost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = Sort airlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, unpaidairlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
function getFlights(cb) {
getAirlines(function (err, airlines) {
if (err) { return cb(err); }
var flightsCost = [];
var airlinesCounter = airlines.length;
airlines.forEach(function (airline, index) {
getCost(airline, function (err, cost) {
if (err) { return cb(err); }
flightsCost[index] = cost;
if (--airlinesCounter === 0) {
var sortedAirlines = sortAirlines(airlines, flightsCost);
cb(null, sortedAirlines);
}
})
});
});
}
Criteria | Callback |
---|---|
overheads | no |
level of nesting | 5 |
visual noise | yes |
separation of data and error | no |
code duplication | yes |
missed error | yes |
linear code | no |
myPromise()
.then(function onSuccess() { return data; },
function onRejected() { ... })
.then(function(data) { ... })
myPromise()
.then(function onSuccess() { return data; },
function onRejected() { ... })
.then(function(data) { ... })
myPromise()
.then(function onSuccess() { return data; },
function onRejected() { ... })
.then(function(data) { ... })
myPromise()
.then(function onSuccess() { return data; },
function onRejected() { ... })
.then(function(data) { ... })
library | time(ms) | memory(MB) |
---|---|---|
callbacks | 211 | 25.57 |
389 | 53.49 | |
785 | 108.14 | |
798 | 102.08 | |
851 | 60.46 | |
1065 | 187.69 | |
1298 | 135.43 | |
2438 | 338.91 |
* results for 10000 parallel executions, 1 ms per I/O op (Original)
function myFunction(arg1, arg2, cb) {
cb(err, result);
}
var myPromisifyFunction = Promise.promisify(myFunction);
myPromisifyFunction()
.then(function() { ... })
function getAirlinesCb(cb) {
setTimeout(function () {
cb(null, 'Airline #123');
}, 0);
}
var getAirlines = Promise.promisify(getAirlinesCb);
function getFlights() {
return getAirlines()
.then(getCosts)
.then(sortAirlines)
.catch(onReject);
}
function getFlights() {
return getAirlines()
.then(getCosts)
.then(sortAirlines)
.catch(onReject);
}
function getCosts(airlines) {
return Promise.props({
airlines: airlines,
flightsCost: Promise.all(airlines.map(getCost))
});
}
function getFlights() {
return getAirlines()
.then(function (airlines) {
return Promise.props({
airlines: airlines,
flightsCost: Promise.all(airlines.map(getCost))
});
})
.then(sortAirlines);
}
getFlights
.then(function (data) { console.log(data); })
.catch(function (err) { console.error(err); });
Criteria | Callback | Promises |
---|---|---|
overheads | no | yes |
level of nesting | 5 | 2 |
visual noise | yes | no |
separation of data and error | no | yes |
code duplication | yes | no |
missed error | yes | no |
linear code | no | yes |
function getFlights() {
var airlines = Get list of airlines()
var flightsCost = airlines.map(Get flight cost);
return Sort airlines(airlines, flightsCost);
};
function getFlights() {
var airlines = getAirlines();
var flightsCost = airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
}
function getFlights() {
var airlines = getAirlinesSync();
var flightsCost = airlines.map(getCostSync);
return sortAirlines(airlines, flightsCost);
}
function *getFlights() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
}
co(function *getFlights() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
}).then(function (data) { console.log(data); });
A generator can pause itself in mid-execution, and can be resumed either right away or at a later time.
ES6
A generator can pause itself in mid-execution, and can be resumed either right away or at a later time.
ES6 ES2015
function *myGenerator(name) {
console.log('Hello, ' + name);
}
function *myGenerator(name) {
console.log('Hello, ' + name);
}
myGenerator('Frontend Union Conf');
>
An iterator is a structured pattern for pulling information from a source in one-at-a-time fashion.
it.next()
{ value: {...}, done: false}
>
function *myGenerator(name) {
console.log('Hello, ' + name);
}
var it = myGenerator('Frontend Union Conf');
it.next();
Hello, Frontend Union Conf
>
var it = fibonacci();
var it = fibonacci();
console.log(it.next().value);
1
>
var it = fibonacci();
console.log(it.next().value);
console.log(it.next().value);
1
1
>
var it = fibonacci();
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
1
1
2
>
var it = fibonacci();
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
1
1
2
3
>
var it = fibonacci();
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
1
1
2
3
5
>
function *fibonacci() {
var fn1 = 1;
var fn2 = 1;
while (true) {
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
yield current;
}
}
function *fibonacci() {
var fn1 = 1;
var fn2 = 1;
while (true) {
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
yield current;
}
}
function *sum() {
var a = yield;
var b = yield;
console.log(a + b);
}
var it = sum();
>
function *sum() {
var a = yield;
var b = yield;
console.log(a + b);
}
var it = sum();
it.next();
>
function *sum() {
var a = 3;
var b = yield;
console.log(a + b);
}
var it = sum();
it.next();
it.next(3);
>
function *sum() {
var a = 3;
var b = 7;
console.log(a + b);
}
var it = sum();
it.next();
it.next(3);
it.next(7);
10
>
function *foo() {
try {
yield;
} catch (e) {
console.error(e.message);
}
}
var it = foo();
it.next()
it.throw(new Error('My error!'))
My error!
>
function *getFlights() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
}
Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way.
var myPromise = co(function *() {
var value = yield Promise.resolve('Hello, #func!');
return value;
});
var myPromise = co(function *() {
var value = yield Promise.resolve('Hello, #func!');
return value;
});
myPromise.then(function (value) {
console.log(value);
});
Hello, #func!
>
var getFlights = co(function *() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
});
var getFlights = co(function *() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
});
getFlights
.then(function (data) { console.log(data); })
.catch(function (err) { console.error(err); });
function getFlights() {
return getAirlines()
.then(function (airlines) {
return Promise.props({
airlines: airlines,
flightsCost: Promise.all(airlines.map(getCost))
});
})
.then(sortAirlines);
}
getFlights
.then(function (data) { console.log(data); })
.catch(function (err) { console.error(err); });
var getFlights = co(function *() {
var airlines = yield getAirlines();
var flightsCost = yield airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
});
getFlights
.then(function (data) { console.log(data); })
.catch(function (err) { console.error(err); });
Criteria | Callback | Promises | Generator |
---|---|---|---|
overheads | no | yes | yes |
level of nesting | 5 | 2 | 1 |
visual noise | yes | no | no |
separation of data and error | no | yes | yes |
code duplication | yes | no | no |
missed error | yes | no | no |
linear code | no | yes | yes |
async function getFlights() {
var airlines = await getAirlines();
var flightsCost = await airlines.map(getCost);
return sortAirlines(airlines, flightsCost);
}
* Measured in iojs-3.0 on mac air
Zhigalov Sergey
Frontend developer
zhigalov@yandex-team.ru
@sergey_zhigalov