Finally
Finally is a simple flow control library for node.js and the browsers, with a mentally sane API.
It works like this
Think of your flow as an array of sequential operations, each one containing an array of parallel operations.
Reading 2 files sequentially
var fs = require('fs')
var flow = require('finally')
flow(function(){
fs.readFile('path/to/file', 'utf-8', this.continue)
})
.then(function(error, data1){
if (error) this.break(error)
fs.readFile('path/to/file', 'utf-8', function(error, data2) {
this.continue(error, data1, data2)
}.bind(this))
})
.finally(function(error, data1, data2){
if (error) throw error
console.log(data1, data2)
})
Reading 2 files in parallel
var fs = require('fs')
var flow = require('finally')
flow(
function(){
fs.readFile('path/to/file', 'utf-8', this.done)
},
function(){
fs.readFile('path/to/file', 'utf-8', this.done)
},
)
.finally(function(error, data1, data2){
if (error) throw error
else console.log(data1, data2)
})
Spreading arguments
var fs = require('fs')
var flow = require('finally')
flow(function(){
fs.readFile('path/to/file.json', function(error, data){
if (error) return this.break(error)
var someObject = JSON.parse(data)
var someArray = someObject.someArray
this.spread(null, someArray)
}.bind(this))
})
.then(function(error, n){
this.done(error, n + 1)
})
.finally(function(error, n1, n2, n3, n4, n5){
if (error) throw error
else console.log(n1, n2, n3, n4, n5)
})
Continuing on error
Say we want to continue on error only, for instance to find the first existing file.
var fs = require('fs')
var flow = require('finally')
flow(function(){
fs.readFile('path/to/file1', function(error, data){
if (error) this.continue(error)
else this.break(null, 'path/to/file1', data)
}.bind(this))
})
.then(function(error, n){
fs.readFile('path/to/file2', function(error, data){
if (error) this.continue(error)
else this.break(null, 'path/to/file2', data)
}.bind(this))
})
.then(function(error, n){
fs.readFile('path/to/file3', function(error, data){
if (error) this.continue(error)
else this.break(null, 'path/to/file3', data)
}.bind(this))
})
.finally(function(error, path, data){
if (error) console.log('no existing file found')
else console.log('first existing file was ' + path + ' with data ' + data)
})
Reading files sequentially, generating the flow
var fs = require('fs')
var flow = require('finally')
var ƒ = flow()
['path/to/file1', 'path/to/file2', 'path/to/file3'].forEach(function(path) {
ƒ.then(function(error){
fs.readFile(path, function(error, data){
if (error) this.continue(error)
else this.break(null, path, data)
}.bind(this))
})
})
ƒ.finally(function(error, path, data){
if (error) console.log('no existing file found')
else console.log('first existing file was ' + path + ' with data ' + data)
})
There is also a shortcut for the above:
var fs = require('fs')
var flow = require('finally')
var ƒ = flow()
ƒ.sequential(['path/to/file1', 'path/to/file2', 'path/to/file3'], function(path, i, error) {
fs.readFile(path, function(error, data){
if (error) this.continue(error)
else this.break(null, path, data)
}.bind(this))
})
ƒ.finally(function(error, path, data){
if (error) console.log('no existing file found')
else console.log('first existing file was ' + path + ' with data ' + data)
})
Reading files in parallel, generating the flow
var fs = require('fs')
var flow = require('finally')
var ƒ = flow()
ƒ(['path/to/file1', 'path/to/file2', 'path/to/file3'].map(function(path) {
return function(error){
fs.readFile(path, function(error, data){
if (error) this.done(error)
else this.break(null, path, data)
}.bind(this))
}
})
ƒ.finally(function(error, path, data){
if (error) console.log('no existing file found')
else console.log('first existing file was ' + path + ' with data ' + data)
})
There is also a shortcut for the above:
var fs = require('fs')
var flow = require('finally')
var ƒ = flow()
ƒ.parallel(['path/to/file1', 'path/to/file2', 'path/to/file3'], function(path, i, error) {
fs.readFile(path, function(error, data){
if (error) this.done(error)
else this.break(null, path, data)
}.bind(this))
})
ƒ.finally(function(error, path, data){
if (error) console.log('no existing file found')
else console.log('first existing file was ' + path + ' with data ' + data)
})