Coroutines - jellyfish-tom/TIL GitHub Wiki
[SOURCES]
Coroutines understand that generators may be hard to predict and reason about in production code and remedy this situation by wrapping a generator and abstracting away all of the complexity.
Coroutines allow us to yield our asynchronous functions one line at a time, making our code look synchronous.
Nowadays (september 2018) mainly two libraries implementing coroutines are used.
- Co
- Bluebird
Let’s establish some basic rules to using coroutines:
- Any function to the right of a yield must return a Promise.
- If you want to execute your code now, use co.
- If you want to execute your code later, use co.wrap.
- Make sure to chain a .catch at the end of your coroutine to handle errors. Otherwise, you should wrap your code in a try/catch block.
- Bluebird’s Promise.coroutine is the equivalent to Co’s co.wrap and not the co function on it’s own.
Syntax:
import co from 'co';
app.post("/purchase", (req, res) => {
co(function* () {
const person = yield user.findOneAsync(req.body);
const permissions = yield permissions.findAllAsync(person);
if (isAllowed(permissions)) {
const confirmNum = yield transaction.processAsync(user);
res.send("Your transaction was successful!")
}
}).catch(err => handleError(err))
});
Note that multiple processes can be run concurrently with single coroutine. Result of it just needs to be destructurized.
import co from 'co';
// with objects
co(function*() {
const {user1, user2, user3} = yield {
user1: user.findOneAsync({name: "Will"}),
user2: user.findOneAsync({name: "Adam"}),
user3: user.findOneAsync({name: "Ben"})
};
).catch(err => handleError(err))
// with arrays
co(function*() {
const [user1, user2, user3] = yield [
user.findOneAsync({name: "Will"}),
user.findOneAsync({name: "Adam"}),
user.findOneAsync({name: "Ben"})
];
).catch(err => handleError(err))
and with Bluebird library:
import {props, all, coroutine} from 'bluebird';
// with objects
coroutine(function*() {
const {user1, user2, user3} = yield props({
user1: user.findOneAsync({name: "Will"}),
user2: user.findOneAsync({name: "Adam"}),
user3: user.findOneAsync({name: "Ben"})
});
)().catch(err => handleError(err))
// with arrays
coroutine(function*() {
const [user1, user2, user3] = yield all([
user.findOneAsync({name: "Will"}),
user.findOneAsync({name: "Adam"}),
user.findOneAsync({name: "Ben"})
]);
)().catch(err => handleError(err))