ES6 generators – Non-Blocking Computations Erik Soehnel github.com/hoeck



ES6 generators – Non-Blocking Computations Erik Soehnel github.com/hoeck

0 1


dresdenjs-generators-part-two


On Github hoeck / dresdenjs-generators-part-two

ES6 generators

and

Non-Blocking Computations

Erik Soehnel
github.com/hoeck

Agenda

Recap: ES6 Generator Syntax Non Blocking: No Callbacks, No Promises Summary, Future

Recap: ES6 Generator Syntax

ES6 Generator Syntax

(codepen)

function* range (start, end) {
    while (start < end) {
        yield start++;
    }
}

const gen = range(5, 7);

gen.next() // => {value: 5, done: false}
gen.next() // => {value: 6, done: false}
gen.next() // => {done: true}

function* defines a generator function yield produces the generators values calling it creates a generator instance next() delivers the generators values next() delivers the generators values until there are no more values

ES6 Generator Syntax

  • available since Node 4
  • on current Firefox, Chrome, Edge
  • always via babel & polyfill
  • check the ES6 compat table

No Callbacks, No Promises

Non-Blocking Code

  • what is JS good at? non-blocking (Asynchronus) Code!
  • what plagues JS? Callbacks!
  • promises are supposed to help ..

Non-Blocking Code

Example: web application handler, synchronous version

function handler (sessionid, response):
    const session = loadSessionSync(sessionid);
    const user = loadUserSync(session.userId);

    response.send(`Hello ${user.name}`);

load a session from the db and wait load a user from the db and wait create the response

web app handler with callbacks

function handler (sessionid, response) {
    loadSession(sessionid, function (err, session) {
        if (err) response.status(500).send();
        loadUser(session.userId, function (err, user) {
            if (err) response.status(500).send();
            response.send(`hello ${user.name}`);
        })
    });
};

load a session from the db, when done, invoke a callback load a user from the db, when done, invoke a callback create and send the response deal with errors in each callback

callbacks

loadUser(userId, function (err, user) {
    response.send(`hello ${user.name}`);
}
  • most naive approach to Non-Blocking code
  • continuation passing style c2wiki
  • hard to follow
  • christmas tree code
  • ...

promises

function handler (sessionid, response) {
    loadSession(sessionid).then(function (session) {
        return loadUser(session.userId);
    }).then(function (user) {
        response.send(`hello ${user.name}`);
    }).catch(function (err) {
        response.status(500).send();
    });
};

load a session from the db, when done, return a promise load a user from the db, when done, return a promoise create and send the response error handling for the promise chain

promises

loadSession(sessionid).then(function (session) {
    return loadUser(session.userId);
})
  • not easy to read and follow
  • provide some level of composability
  • better error handling with .catch
  • they're an important building block

with generators

function * handler (sessionid, response) {
    const session = yield loadSession(sessionId);
    const user = yield loadUser(session.userId);

    response.send(`hello ${user.name}`);
}

load a session from the db, when done, keep it in session load a user from the db, when done, keep it in user create and send the response errors are thrown and can be catched (e.g. by the framework)

with generators

// blocking
function handler (sessionid, response) {
    const session = loadSessionSync(sessionid);
    const user = loadUserSync(session.userId);

    response.send(`Hello ${user.name}`);
}

// non-blocking
function * handler (sessionid, response) {
    const session = yield loadSession(sessionId);
    const user = yield loadUser(session.userId);

    response.send(`hello ${user.name}`);
}

the same, except yield the same, except yield

the non blocking version is the same as the blocking one

Generators are an

Awesome
Abstraction

Non-Blocking Code

with generators

  • looks similar to synchronous code
  • error handling via exceptions
  • interoperates well with promises

Promise Interactions

to actually write non-blocking generator code

  • web framework: koa
  • library: co
  • promises for nodejs APIs mz

co example

downloading files

import co from co;
import fs from 'mz/fs';
import request from 'request-promise';

const loadFiles = co.wrap(function* (targets) {
    for (target of targets) {
        const data = yield request.get(target.url);
        yield fs.writeFile(target.name, data);
    }
});

loadFiles(files).then(() => {
    console.log('done');
}).catch((err) => {
    console.log(err.stack);
});

co: transforms a generator into a promise mz/fs: nodejs filesystem module using promises request-promise: http client using promises

the generator co.wrap turns a generator into a Promise loop through all targets request.get(target.url) fetches an url and returns a Promise yield takes the promise and passes execution to co const data: once the promise is resolved, co consumes the generator fs.writeFile writes data to a file, when done, the loop continues

calling loadFiles returns a promise

and the future

ES7 async & await

function * handler (sessionid, response) {
    const session = yield loadSession(sessionId);
    const user = yield loadUser(session.userId);

    response.send(`hello ${user.name}`);
}
const promise = co.wrap(handler)(sessionid, response);

// turns into
async function handler () {
    const session = await loadSession(sessionId);
    const user = await loadUser(session.userId);

    response.send(`hello ${user.name}`);
}
const promise = handler(sessionid, response);

function * async function yield await and you don't need co

summing up

  • generators let you trivially write non-blocking code
  • they're supported by babel and nodejs
  • there is framework and library support
  • you can start using them today
  • in the future you will use async & await

summing up

codepen.io/shnel/pen/VjeKwL

Thanks

ES6 generators and Non-Blocking Computations Erik Soehnel github.com/hoeck