Unchain promises
Ramify is a lightweight library with zero dependencies which provides a simple way to create complex paths of functions and promises for easier handling the different scenarios that can happen in a chain of actions.
It supports both browser and Node.js environments. At a browser it exposes a global variable, Ramify
.
Attention: The Ramify package is still in beta. Breaking changes may be introduced at any point. Use carefully.
Using npm:
npm install --save ramify
var Ramify = require('ramify');
// or
import Ramify from 'ramify';
var myController = new Ramify();
Using Bower:
bower install --save ramify
<script src="dist/ramify.min.js"></script>
<script type="text/javascript">
var myController = new Ramify();
</script>
Simple synchronous example
var myController = new Ramify();
myController.addAll({
one: function () {
this.call('two', Math.round(Math.random() * 10));
},
two: function (param) {
if (param > 8) {
this.call('three', param * 2);
} else if (param > 3) {
this.call('four', param * 2);
} else {
throw new Error('Just an error!');
}
},
three: function (param) {
document.querySelector('#main').innerHTML = 'Three: ' + param * 2;
},
four: function (param) {
document.querySelector('#main').innerHTML = 'Four: ' + param * 3;
}
}).catch(function (err) {
console.log(err);
}).call('one');
Asynchronous example
function myPromise (param) {
return new Promise(function (resolve) {
resolve(param + 5);
});
}
var myController = new Ramify();
myController.addAll({
func1: function () {
return this.call('func2', Math.round(Math.random() * 10), Promise.reject);
},
func2: function (param) {
if (param > 8) {
return this.call('func3', param * 2);
} else if (param > 3) {
return this.call('func4', param * 2);
} else {
throw new Error('Just an error!');
}
},
func3: function (param) {
return Promise.resolve('aaa: ' + param * 2);
},
func4: function (param) {
return this.call('func5', myPromise(param).delay(600));
},
func5: function (param) {
return this.call('func6', myPromise(param).delay(600));
},
func6: function (param) {
return Promise.resolve('bbb: ' + param * 3);
}
}).catch(Promise.reject);
var result = myController.call('func1');
result.then(function (result) {
document.querySelector('#main').innerHTML = result;
}).catch(Ramify.RamifyError, function (err) {
console.log('RamifyError');
console.log(err.stack);
}).catch(function (err) {
console.log(err.stack);
});
More complex asynchronous example
var shopsService = new Ramify();
var rami = {};
function _findShop (name) {
return new Promise(function (resolve, reject) {
var temp = Math.random();
if (temp > 0.7) {
// could not find shop with this name
resolve([]);
} else if (temp > 0.4) {
// shop found
resolve([{
id: '765454654565',
name: name
}]);
} else {
// An error occured while fetching from db
reject(new Error('Something went wrong!'));
}
});
}
function _createShop (name) {
return new Promise(function (resolve) {
// create shop and return it
resolve({
id: '12342432423',
name: name
});
});
}
rami.findOrCreateShop = function (shopName) {
console.log('- Trying to find the shop');
this.prop('shopName', shopName);
var count = this.prop('count');
this.prop('count', Number.isInteger(count) ? count + 1 : 1);
console.log('Trying to find the shop. Try: ' + this.prop('count'));
return this.call('handleFindShopResponse', _findShop(shopName),
function errorHandler(err) {
if (err instanceof Ramify.RamifyError) {
throw err;
}
console.log(err.message);
if (this.prop('count') < 3) {
return this.call('findOrCreateShop', this.prop('shopName'));
} else {
throw new Error('Retry limit reached.');
}
});
};
rami.handleFindShopResponse = function (shops) {
console.log('Shop found after ' + this.prop('count') + ' tries');
if (shops.length > 0) {
console.log('- Shop found');
return this.call('constructResponse', shops[0]);
} else {
console.log('- Couldn\'t find shop, creating one');
return this.call('handleCreateShopResponse', _createShop(this.prop('shopName')));
}
};
rami.handleCreateShopResponse = function (newShop) {
console.log('- Shop created');
return this.call('constructResponse', newShop);
};
rami.constructResponse = function (shop) {
console.log('- Returning the shop');
shop.website = 'https://' + shop.name;
return shop;
};
shopsService.addAll(rami).catch(Promise.reject);
shopsService.call('findOrCreateShop', 'myshop.com')
.then(function (shop) {
document.querySelector('#main').innerHTML = JSON.stringify(shop);
}).catch(Ramify.RamifyError, function (err) {
console.log('+++++ Ramify Error +++++');
console.log(err.stack);
}).catch(function (err) {
console.log('+++++ General Error +++++');
console.log(err.stack);
});
Unsafe alias asynchronous example
// index.js
var ShopsService = require('./service.js');
ShopsService.findOrCreateShop('myshop.com')
.then(function (shop) {
console.log('Success!');
console.log(shop);
}).catch(ShopsService.RamifyError, function (err) {
console.log('+++++ Ramify Error +++++');
console.log(err.stack);
}).catch(function (err) {
console.log('+++++ General Error +++++');
console.log(err.stack);
});
// service.js
var Ramify = require('ramify');
var DB = require('./db.js');
var shopsService = new Ramify({
createAlias: true,
safeAlias: false
});
shopsService.add(function findOrCreateShop (shopName) {
console.log('- Trying to find the shop');
this.prop('shopName', shopName);
var count = this.prop('count');
this.prop('count', Number.isInteger(count) ? count + 1 : 1);
console.log('Trying to find the shop. Try: ' + this.prop('count'));
return this.handleFindShopResponse(DB.findShop(shopName),
function errorHandler(err) {
if (err instanceof Ramify.RamifyError) {
throw err;
}
console.log(err.message);
if (this.prop('count') < 3) {
return this.findOrCreateShop(this.prop('shopName'));
} else {
throw new Error('Retry limit reached.');
}
});
});
shopsService.add(function handleFindShopResponse (shops) {
console.log('Shop found after ' + this.prop('count') + ' tries');
if (shops.length > 0) {
console.log('- Shop found');
return this.constructResponse(shops[0]);
} else {
console.log('- Couldn\'t find shop, creating one');
return this.handleCreateShopResponse(DB.createShop(this.prop('shopName')));
}
});
shopsService.add(function handleCreateShopResponse (newShop) {
console.log('- Shop created');
return this.constructResponse(newShop);
});
shopsService.add(function constructResponse (shop) {
console.log('- Returning the shop');
shop.website = 'https://' + shop.name;
return shop;
});
module.exports = shopsService;