Skip to content

Instantly share code, notes, and snippets.

@getify
Last active August 9, 2020 04:09
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save getify/8459026 to your computer and use it in GitHub Desktop.
Save getify/8459026 to your computer and use it in GitHub Desktop.
example: refactoring some code (in keystonejs) from "callback hell"-style to asynquence-style
var doQuery = function() {
count.exec(function(err, total) {
if (err) return sendError('database error', err);
query.exec(function(err, items) {
if (err) return sendError('database error', err);
sendResponse({
total: total,
items: items.map(function(i) {
return {
name: req.list.getDocumentName(i, true) || '(' + i.id + ')',
id: i.id
};
})
});
});
});
}
// [Update: this is the "old" way now, which sucks. see the next 2 files in this gist]
var doQuery = function() {
// fetch total
function fetchTotal(done){
count.exec(function(err, total) {
// note: `return` here does nothing for asynquence, only
// exits the function early. :)
if (err) return done.fail('database error', err);
done(total); // pass along `total` as a value-message
});
}
// fetch items
function fetchItems(done){
query.exec(function(err, items) {
// note: `return` here does nothing for asynquence, only
// exits the function early. :)
if (err) return done.fail('database error', err);
done(items); // pass along `items` as value-message
});
}
// transform the data to prepare it for `sendResponse()`
function prepareData(total, items){
return {
total: total,
items: items.map(function(i) {
return {
name: req.list.getDocumentName(i, true) || '(' + i.id + ')',
id: i.id
};
})
};
}
// behold, the elegant beauty of clean async flow-control
ASQ()
// fetch total and items in parallel
.gate(
fetchTotal,
fetchItems
)
// prepare data
.val(prepareData)
// now, send the transformed data along
.val(sendResponse)
// handle any errors that propagate up to here
.or(sendError);
}
// [Update: this now works!]
var doQuery = function() {
// fetch total
function fetchTotal(done){
count.exec(done.errfcb); // <-- Look ma, no code!
}
// fetch items
function fetchItems(done){
query.exec(done.errfcb); // <-- Look ma, no code!
}
// transform the data to prepare it for `sendResponse()`
function prepareData(total, items){
return {
total: total,
items: items.map(function(i) {
return {
name: req.list.getDocumentName(i, true) || '(' + i.id + ')',
id: i.id
};
})
};
}
// behold, the elegant beauty of clean async flow-control
ASQ()
// fetch total and items in parallel
.gate(
fetchTotal,
fetchItems
)
// prepare data
.val(prepareData)
// now, send the transformed data along
.val(sendResponse)
// handle any errors that propagate up to here
.or(sendError);
}
// [Update: even way better, this now works]
var doQuery = function() {
// transform the data to prepare it for `sendResponse()`
function prepareData(total, items){
return {
total: total,
items: items.map(function(i) {
return {
name: req.list.getDocumentName(i, true) || '(' + i.id + ')',
id: i.id
};
})
};
}
// behold, the elegant beauty of clean async flow-control
var sq = ASQ();
// fetch total and items in parallel
count.exec( sq.errfcb() );
query.exec( sq.errfcb() );
sq
// prepare data
.val(prepareData)
// now, send the transformed data along
.val(sendResponse)
// handle any errors that propagate up to here
.or(sendError);
}
@benjamingr
Copy link

While we're discussing promises, here is how I'd do this with promises.

var api = Promise.promisifyAll({count:count,query:query}); //convert our API to promises

var count = api.count(); // calls for eventual values are as simple as normal API calls
var exec = api.exec(); // there is no cruft here :)
var items = count.map(function(i){ // map the count
      return { id: i.id, name: req.list.getDocumentName(i, true) || "(" + i.id +")" };
});
Promise.all(count,items).then(function(c,i){ // all ready
    return count.map(function(){
        return { total: c, items: i};
    });
}).then(sendResponse).catch(sendError);

@ClarkMiaguo
Copy link

@gerify regarding gistfile4.js This should not work.
var sq = ASQ();

// fetch total and items in parallel
count.exec( sq.errfcb() );
query.exec( sq.errfcb() );

sq
// prepare data

.val(prepareData) // then only query result

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment