orc

0.0.17 • Public • Published

orc

It is customary in computer programming to take a collection of statements that might be difficult to understand and place them behind a name, within a function, so that they may be more easily understood and reused. In a language like JavaScript if any of these statements are separated by an event then putting the statements all in one function is very difficult. Orc makes this trivial.

This problem with asynchrony in JavaScript/CoffeeScript is well-known and best illustrated with an example. The following programs both do the same thing: 1) load some content, and then 2) render that content. The first is written without orc:

loadData = ->
    console.log 'load the data and wait'
    http = require 'http'
    options =
        host: 'google.com'
        port: 80
        path: ''
 
    handleHTTPGet = (response) ->
        response.setEncoding 'utf8'
 
        handleData = (chunk) ->
            console.log "data loaded #{chunk}"
 
        response.on 'data'handleData
 
        # here we wait as well 
        response.on 'end'renderContent
 
    # here we wait 
    http.get optionshandleHTTPGet
 
renderContent = ->
    console.log 'now render the page'
 
 
# this is where we initiate the sequence 
loadData()

The overall flow here is:

  1. loadData()
  2. renderContent()

Understanding this flow requires reading through the program. It would be better if you could put loadData and renderContent next to eachother:

orc = require('./src/orc').orc
 
loadData = ->
    console.log 'load the data and wait'
    http = require 'http'
    options =
        host: 'google.com'
        port: 80
        path: ''
 
    handleHTTPGet = (response) ->
        response.setEncoding 'utf8'
 
        handleData = (chunk) ->
            console.log "data loaded #{chunk}"
 
        response.on 'data'handleData
 
        # here we wait as well 
        response.on 'end'orc.waitFor()
 
    # here we wait 
    http.get optionsorc.waitFor(handleHTTPGet)
 
renderContent = ->
    console.log 'now render the page'
 
 
# this is where we initiate the sequence 
orc.sequence loadDatarenderContent

The important differences are obviously the orc.sequence and two orc.waitFor calls. Both of these programs have the same output:

$ coffee example.coffee
load the data and wait
data loaded <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
 
now render the page

You can see that first the content is loaded and only after that is the content rendered.

Getting Started

1) Get orc from npm or bower

# if you're using with node install with npm 
npm install orc
 
# if you're using in the browser install with bower 
bower install orc

2) Require or script tag orc

orc = require('orc').orc
<script src="orc.js"></script>

3) Sequence some functions

loadContent = ->
renderContent = ->
 
orc.sequence loadContentrenderContent

4) Wait for some stuff

loadContent = ->
  request = loader.get someDataUrl
  request.on 'data'orc.waitFor(parseData)
 
renderContent = ->
  animator.do animationOptions orc.waitFor()
 
orc.sequence loadContentrenderContent

5) Tell orc how to error

loadContent = ->
  request = loader.get someDataUrl
  request.on 'data'orc.waitFor(parseData)
  request.on 'error'orc.errorOn()
 
renderContent = ->
  animator.do animationOptions orc.waitFor()
 
orc.sequence loadContentrenderContent

6) Handle sequence error instead of erroring

loadContent = ->
  request = loader.get someDataUrl
  request.on 'data'orc.waitFor(parseData)
  request.on 'error'orc.errorOn()
 
renderContent = ->
  animator.do animationOptions orc.waitFor()
 
context = orc.sequence loadContentrenderContent
context.handleError = (error, context) -> console.log "#{error} for #{context}"

That's it.

How does it work?

Orc does as much of the bookkeeping as it can. You should almost never need anything more than the sequence, waitFor, and errorOn functions. Like anything else the more you know about orc the easier it is to work with.

sequence

Everything begins with you telling orc to sequence some functions. Orc places these condemned functions into an ExecutionContext. The context lets orc keep the details of each execution separated. These details are things like the functions being executed and whether or not the execution is on hold for anything. At this point orc will begin executing, if it's not already.

Orc can execute both dependent and independent sequences. A sequence is dependent when it requires another sequence to complete before it completes. Dependent sequences are called inside of other sequences kinda like this:

orc.sequence ->
  orc.sequence ...

Independent sequences on the other hand look kinda like this:

orc.sequence ...
orc.sequence ...

Whether or not one sequence depends on another sequence determines where orc puts the execution context. If the sequence is independent orc will add it alongside whatever other contexts exist. If the sequence is dependent orc will stack the context on top of whichever context depends on it. Orc then manages these dependencies by only executing from the context at the top of of each stack.

waitFor

The waitFor decorator is simple. First it saves the current context so that later on it can determine which context the decorated function belongs to. Then it returns a function that wraps the callback it was provided.

The decorated function that waitFor returns will set the current context to the context that was saved earlier. This ensures that any waitFor calls made during the callback will be routed to the correct context. At the very end, once it has executed the callback, the waitFor function will call done on the correct context.

Readme

Keywords

none

Package Sidebar

Install

npm i orc

Weekly Downloads

16

Version

0.0.17

License

none

Last publish

Collaborators

  • michaelavila