Last active
December 27, 2015 18:29
-
-
Save briancavalier/7370665 to your computer and use it in GitHub Desktop.
"Promisify" a business object using an internal queue to serialize async operations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var when = require('when'); | |
var delay = require('when/delay'); | |
var slice = Array.prototype.slice; | |
var promisePrototype = Object.getPrototypeOf(when.resolve()); | |
//--------------------------------------------------------- | |
// A simple business object | |
//--------------------------------------------------------- | |
function MyObj() { | |
this._queue = when.resolve(); | |
this.value = 0; | |
} | |
//--------------------------------------------------------- | |
// MyObj's prototype | |
// We'll promisify this and then set it as MyObj's prototype | |
// These methods are allowed to return promises | |
//--------------------------------------------------------- | |
var methods = { | |
call1: function(x) { | |
// Implement call1 with whatever business logic you need | |
console.log('call1 business logic', x); | |
this.value += x; | |
return this.value; | |
}, | |
call2: function(x) { | |
// Implement call2 with whatever business logic you need | |
console.log('call2 business logic', x); | |
this.value += x; | |
// For fun, return a delayed value | |
return delay(1000).yield(this.value); | |
}, | |
call3: function(x) { | |
// Implement call3 with whatever business logic you need | |
console.log('call3 business logic', x); | |
this.value += x; | |
return this.value; | |
} | |
}; | |
//--------------------------------------------------------- | |
// Set MyObj's prototype by creating queueing versions of its | |
// methods, and then adding the promise API (then, otherwise, etc.) | |
// to provide access to the current queue value. | |
//--------------------------------------------------------- | |
MyObj.prototype = mixinPromiseMethods(makeQueuedMethods(methods), promisePrototype); | |
//--------------------------------------------------------- | |
// Here's how you can use it | |
//--------------------------------------------------------- | |
var ob = new MyObj() | |
ob.call1(1) | |
.call2(2) | |
.call3(3) | |
.then( function(result) { console.log( result ); }) | |
.otherwise( function(err) { console.log( err ); }); | |
//--------------------------------------------------------- | |
// Helpers for promisifying methods and adding promise API | |
//--------------------------------------------------------- | |
// Promisify business logic methods | |
function makeQueuedMethods(methods) { | |
return Object.keys(methods).reduce(function (prototype, methodName) { | |
prototype[methodName] = function () { | |
var args = slice.call(arguments); | |
var self = this; | |
this._queue = when(this._queue, function () { | |
return methods[methodName].apply(self, args); | |
}); | |
return this; | |
}; | |
return prototype; | |
}, {}); | |
} | |
// Add promise API, routing to internal queue | |
function mixinPromiseMethods(prototype, promisePrototype) { | |
return Object.keys(promisePrototype).reduce(function(prototype, methodName) { | |
prototype[methodName] = function() { | |
return this._queue[methodName].apply(this._queue, slice.call(arguments)); | |
}; | |
return prototype; | |
}, prototype); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment