Converting to async.waterfall - javascript

I have following code
function someHelper(someList) {
return someList.map((item) => {
return (next) => someService.firstCall(paramForFirst, (err, result) => {
if(err) next(err);
else someService.secondCall(paramForSecond, result, next);
})
});
}
module.exports = {
doSomething(param, callback) {
async.parallel(someHelper(someList), callback);
}
};
How I can convert second return of someHelper function to use async.waterfall?

Here is the solution I have. Pass the next(callback) from parallel and then call methods in waterfall array list and finally call the next at the end. By defination waterfall will call callback with result or error.
function someHelper(someList) {
return someList.map((item) => {
return (next) => {
async.waterfall([
async.apply(someService.firstCall, paramForFirst),
async.apply(someService.secondCall, paramForSecond)
], next);
}
});
}

Related

Wrapping async functions with callbacks within

I need to call two async functions sequentially inside a new function. Both functions use callbacks to perform asynchronous operations.
When I just call my functions one by one I am faced with the problem that, as I understand it, they are called synchronously, and the second function does not wait for the first to execute
How can I wrap them to be performed sequentially?
Code that I have:
let firstFunction = (data, callback) => {
DBCallingFirst
.asyncMethodFirst(resultObj, (err, result) => {
if (err) return callback(err);
// Some code
});
}
let secondFunction = (data, callback) => {
DBCallingSecond
.asyncMethodSecond(resultObj, (err, result) => {
if (err) return callback(err);
// Some code
});
}
let newFunction = (data, callback) => {
firstFunction(data, callback);
secondFunction(data, callback);
}
Thanks for your attention!
If you are able to use promises, or async/await, you can make this a lot cleaner. As it is, you can just do the second db operation in the callback from the first one - so that guarantees the first one completes before calling the second
let firstFunction = async (data, callback) => {
DBCallingFirst
.asyncMethodFirst(resultObj, (err, result) => {
if (err) return callback(err);
DBCallingSecond
.asyncMethodSecond(resultObj, (err, result) => {
if (err) return callback(err);
// Some code
});
});
}
EDIT: With promises, you could structure it like this:
let firstFunction = (data) => {
return new Promise(() => {
DBCallingFirst
.asyncMethodFirst(data, (err, result) => {
if (err) {
return Promise.reject();
}
return Promise.resolve(result);
});
});
}
let secondFunction = (data) => {
return new Promise(() => {
DBCallingSecond
.asyncMethodSecond(data, (err, result) => {
if (err) {
return Promise.reject();
}
return Promise.resolve(result);
});
});
}
let newFunction = (data, callback) => {
firstFunction(data).then((result1) => {
secondFunction(data).then(result2) {
}).catch(err2) {
console.error(err2);
});
}.catch((err1) => {
console.error(err1);
});
}
Return Promise from both the functions and await them like this
const firstFunction = (data) => {
return new Promise((resolve, reject) => {
DBCallingFirst.asyncMethodFirst(data, (err, result) => {
if(err) reject(err);
resolve(result);
})
})
}
const secondFunction = (data) => {
return new Promise((resolve, reject) => {
DBCallingSecond.asyncMethodSecond(data, (err, result) => {
if(err) reject(err);
resolve(result);
})
})
}
Now you can call both of them sequentially using await
const newFunction = async (data) => { // note the async part in function definition
try {
const result1 = await firstFunction(data);
const result2 = await secondFunction(data); // this will be executed only after firstFunction resolves/rejects;
} catch (err) {
console.log('Error from the function', error) // promise rejection will be caught here
}
}

undefined var module.exports

For some reason, I can't get values returned from module.exports function from a separate custom module. I tried many ways from many sources from >10s researched posts. If you want to vote down, please read my bio or if you want to help I will be happy to accept your answer.
// restapi/index.js
module.exports = function gifs() {
giphy.search('Pokemon', function (err, res) {
return res.data[0];
});
}
// main server.js
var readapi = require('restapi')
console.log(readapi.gifs());
// Output:__________________
TypeError: readapi.gifs is not a function
You are exporting a function, not an object with a function and you are using a sync function (console.log) with an async operation.. it won't work.
You need to write it like this:
module.exports = function gifs(cb) {
giphy.search('Pokemon', function (err, res) {
if(err) { cb(err) }
else { cb(null, res.data[0]) }
});
}
----
var readapi = require('restapi')
readapi((err, data) => { console.log({err, data}) })
Remember the difference between:
module.export = {
hello: () => { console.log('world') }
}
// usage: require('./hello').hello()
module.export = () => { console.log('world') }
// usage: require('./hello')()
Try this code
module.exports.gifs = function gifs() {
return new Promise((resolve, reject) => {
giphy.search('Pokemon', function (err, res) {
if (err) reject(err);
else resolve(res.data[0]);
});
});
}
// main server.js
var readapi = require('restapi')
readapi.gifs().then(console.log);

How to prevent second callback within called function

I am trying to execute following array (avoid callbackHell) of functions(sync/async), in a sequential order, implementing function runCallbacksInSequence (I need to implement my own function to understand how callbacks work and avoid using Async.js).
Here is what I have so far. The function runCallbacksInSequence works well till it gets the same callback cb(null, 'one'); the second time. Ideally if it gets the same callback more than once it should not execute it second time and ignore it.
If you have any ideas let me know how I can implement it. - no promises and async/await
function first(cb) {
setTimeout(function() {
console.log('first()');
cb(null, 'one');
cb(null, 'one');//not supposed to be execute by runCallbacksInSequence
}, 0);
}
function last(cb) {
console.log('last()');
cb(null, 'lastCall');
}
function runCallbacksInSequence(fns, cb) {
fns.reduce(
(r, f) => {
return k => {
return r(() => {
return f((e, x) => {
return e ? cb(e) : k(x);
});
});
};
},
k => {
return k();
}
)(r => {
return cb(null, r);
});
}
fns = [first, last];
runCallbacksInSequence(fns, function(err, results) {
if (err) return console.log('error: ' + err.message);
console.log(results);
});

How to create three function with same name one is callback, second is promise other is async/await

I want to create a function which can be utilised in 3 ways for creating npm dependency
Promise way
callback way
async/await way
For Example
1) async/await
var mongoose = require('mongoose');
async function Connection() {
try {
await mongoose.connect('mongourl');
} catch (err) {
console.error("Connection error --->", err);
}
}
Connection();
2) Callback Style
var mongoose = require('mongoose');
mongoose.connect('mongourl', function (err) {
if (err) console.error("Connection error --->", err);
});
3) Promise Style
var mongoose = require('mongoose');
mongoose.connect('mongourl').then(() => {
}).catch(err => console.error("Connection error --->", err));
Did u absorve that mongoose.connect is same name for all types
You can try with:
const connect = (name, callback) => {
try {
const result = /* generate result */
if (callback) {
callback(null, result);
} else {
return Promise.resolve(result);
}
} catch (e) {
if (callback) {
callback(e);
} else {
return Promise.reject(e);
}
}
}
And quick usage example:
connect('John')
.then(result => { /* ... */ })
.catch(error => { /* ... */ });
connect('John', (error, result) => { /* ... */ });
async function foo() {
try {
const result = await connect('John');
} catch (error) { /* ... */ }
}
Here is an example, it's similar to #hsz, but I've put the handling for the inner callback.
If your pass a callback it does this in a callback way, if not it returns a Promise instead.
If you run the snippet you can see it in action.
I've basically created a simple setTimeout function that randomly fails, to show how error handling is also done. So to see the full effect try running the snippet a few times.
function doInner(name, callback) {
setTimeout(() => {
if (Math.random() < 0.5)
callback(null, "Did " + name);
else callback(new Error("Oops in " + name));
}, 1000);
}
function doSomething(name, callback) {
if (callback) {
doInner(name, (err, result) => {
if (callback) callback(err, result);
});
} else return new Promise((resolve, reject) => {
doInner(name, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
}
//now lets test both ways
doSomething("test callback", (err, result) => {
if (err) console.error(err);
else console.log(result);
});
(async function () {
try {
const result = await doSomething("Promise");
console.log(result);
} catch(e) {
console.error(e);
}
}());

Async-WaterFall not working as expected

waterfall function with two calls but the second on is not waiting for the first one to completely finish. The first one has a mongodb.find() call in it.
Here is the async-waterfall function
app.get("/news", function(req, res) {
async.waterfall([
function (callback) {
var blogs = tendigiEngine.getAllBlogs(callback);
callback(null, blogs);
},
function (blogs, callback) {
var array = tendigiEngine.seperateBlogs(blogs, callback);
callback(null, array );
}
], function (err, result) {
// result now equals 'done'
console.log("done");
console.log(result);
});
});
Here are the two functions being called:
getAllBlogs():
exports.getAllBlogs = function() {
Blog.find(function(err, theBlogs){
if(!err) {
return theBlogs;
}
else {
throw err;
}
});
}
seperateBlogs():
exports.seperateBlogs = function(blogs) {
if(blogs.length === 0 ) {
return 0;
}
else {
blogs.reverse();
var blog = blogs[0];
blogs.shift();
var finArray = [blog, blogs];
return finArray;
}
console.log("asdf");
}
It is important that seperateBlogs won't be called before getAllBlogs() has returned theBlogs, but it is being called before the value is returned. I used Async_Waterfall to avoid this problem but it keeps recurring, which means I am using it wrong. What am I doing wrong here and how can I fix it?
Thanks!
Your exported functions are missing the callback parameters:
exports.getAllBlogs = function(cb) {
Blog.find(cb);
};
exports.seperateBlogs = function(blogs, cb) {
if (blogs.length === 0 )
return cb(null, blogs);
blogs.reverse();
var blog = blogs[0];
blogs.shift();
cb(null, [blog, blogs]);
}
Then your main code can be simplified as well:
async.waterfall([
tendigiEngine.getAllBlogs,
tendigiEngine.seperateBlogs
], function (err, result) {
// result now equals 'done'
console.log("done");
console.log(result);
});

Categories

Resources