I'm trying to rebuild a process based on reading an article here: https://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/
The code below throws an error, I realise now because theResults.org is not a promise by the time the process tries to use theResults.org.then(), but you can probably see what I'm trying to achieve. I want to set everything up so that rather than dictating control flow I just make sub processes dependant on the data coming into the promises, but I'm lost on how to get some of the chaining right.
After validation, the org must be created, then when it exists, the context is created etc etc. I know I'm missing a key understanding here - can anyone point out to me the step or syntax I'm getting wrong please? 'use strict'
var q = require('q');
module.exports["purchaseSchool"] = function(req, successCB, failCB) {
try {
//var purchaseData = req.body.formData;
var purchaseData = "";
var theResults = {
bValidated: null,
org: null,
context: null,
cohort: null,
invoice: null,
bInvoiced: null,
bEmailed: null
}
// validate the data
theResults.bValidated = validatePurchaseData(purchaseData);
theResults.bValidated.then(function () {
// DEBUG: remove this
console.log("validated");
theResults.org = createOrg(purchaseData);
});
theResults.org.then(function() {
// DEBUG: remove this
console.log("org");
theResults.context = createContext(purchaseData, theResults.org);
});
theResults.context.then(function() {
// DEBUG: remove this
console.log("context");
theResults.cohort = createCohort(purchaseData, theResults.context);
});
theResults.cohort.then(function() {
// DEBUG: remove this
console.log("cohort");
theResults.invoice = createInvoice(purchaseData);
});
theResults.invoice.then(function() {
// DEBUG: remove this
console.log("invoice");
theResults.bInvoiced = sendInvoice(theResults.invoice);
});
theResults.bInvoiced.then(function() {
// DEBUG: remove this
console.log("invoice sent");
theResults.bEmailed = sendPurchaseEmail(purchaseData);
});
theResults.bEmailed.then(function() {
// DEBUG: remove this
console.log("emailed");
successCB("Purchase Complete");
});
} catch (err) {
console.log(err);
console.log(err.stack);
failCB();
}
};
function validatePurchaseData(data) {
var defer = q.defer();
setTimeout(function(){ defer.resolve(true) }, 5000);
return defer.promise;
}
function createOrg(org) {
var defer = q.defer();
setTimeout(function(){ defer.resolve({id:"org"}) }, 5000);
return defer.promise;
}
function createContext(data, org) {
var defer = q.defer();
setTimeout(function(){ defer.resolve({id:"context"}) }, 5000);
return defer.promise;
}
function createCohort(data, context) {
var defer = q.defer();
setTimeout(function(){ defer.resolve({id:"cohort"}) }, 5000);
return defer.promise;
}
function createInvoice(data) {
var defer = q.defer();
setTimeout(function(){ defer.resolve({id:"invoice"}) }, 5000);
return defer.promise;
}
function sendInvoice(invoice) {
var defer = q.defer();
setTimeout(function(){ defer.resolve(true) }, 5000);
return defer.promise;
}
function sendPurchaseEmail(data) {
var defer = q.defer();
setTimeout(function(){ defer.resolve(true) }, 5000);
return defer.promise;
}
As is often the case, posing the question helped me find the answer. There are probably more elegant ways to do this, perhaps using q.all to handle the final return ( and I'd love to hear any pointers on doing it better) but here's what made it work:
'use strict'
var q = require('q');
module.exports["purchaseSchool"] = function (req, successCB, failCB) {
// DEBUG: remove this
console.log("blah1");
try {
//var purchaseData = req.body.formData;
var purchaseData = "";
var theResults = {
bValidated: null,
org: null,
context: null,
cohort: null,
invoice: null,
bInvoiced: null,
bEmailed: null
}
// validate the data
theResults.bValidated = validatePurchaseData(purchaseData);
theResults.org = theResults.bValidated.then(function (bValidated) {
// DEBUG: remove this
console.log("blah2");
return createOrg(purchaseData);
});
theResults.context = theResults.org.then(function (org) {
return createContext(purchaseData, org);
});
theResults.cohort = theResults.context.then(function (context) {
return createCohort(purchaseData, context);
});
theResults.invoice = theResults.cohort.then(function (cohort) {
return createInvoice(purchaseData);
});
theResults.bInvoiced = theResults.invoice.then(function (invoice) {
return sendInvoice(invoice);
});
theResults.bEmailed = theResults.bInvoiced.then(function (bInvoiced) {
return sendPurchaseEmail();
});
theResults.bEmailed.then(function (bEmailed) {
successCB("Purchase Complete");
});
} catch (err) {
console.log(err);
console.log(err.stack);
failCB();
}
};
function validatePurchaseData(data) {
var defer = q.defer();
setTimeout(function () {
defer.resolve(true)
}, 1000);
return defer.promise;
}
function createOrg(org) {
var defer = q.defer();
setTimeout(function () {
defer.resolve({id: "org"})
}, 1000);
return defer.promise;
}
function createContext(data, org) {
var defer = q.defer();
setTimeout(function () {
defer.resolve({id: "context"})
}, 1000);
return defer.promise;
}
function createCohort(data, context) {
var defer = q.defer();
setTimeout(function () {
defer.resolve({id: "cohort"})
}, 1000);
return defer.promise;
}
function createInvoice(data) {
var defer = q.defer();
setTimeout(function () {
defer.resolve({id: "invoice"})
}, 1000);
return defer.promise;
}
function sendInvoice(invoice) {
var defer = q.defer();
setTimeout(function () {
defer.resolve(true)
}, 1000);
return defer.promise;
}
function sendPurchaseEmail(data) {
var defer = q.defer();
setTimeout(function () {
defer.resolve(true)
}, 1000);
return defer.promise;
}