Insert functions via for loop to async [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
I have the following function:
module.exports = {
listAccounts: function (callback) {
var acc = [];
var calls = [];
function processAccounts(account, cb) {
client.getAddressesByAccount(account, function (err, addresses) {
console.log('getting account', account);
acc.push({name: account, addresses: addresses});
return cb();
});
}
client.listAccounts(function (err, res) {
if (err)
return callback(err)
else {
for (var key in res) {
calls.push(
function (cb) {
processAccounts(key, cb);
}
);
}
async.parallel(calls, function (err, results) {
console.log(acc);
})
}
})
}
}
What I want to do is to use the for loop in order to push all the functions to the calls array and then run async.parallel to run all the functions.
The problem is, that the calls array looks like this after the for loop finishes:
function (cb) {
processAccounts(key, cb);
},function (cb) {
processAccounts(key, cb);
},function (cb) {
processAccounts(key, cb);
}
It does not translate the key to the actual value but keeps it as key

Use function to create a new scope where the value can be container in the closure.
var res = {a:'hello', b:'howdy'};
var calls = [];
for (var key in res) {
calls.push(
(function(k) {
return function (cb) {
console.log('say: ' + res[k] + ' to ' + cb);
}
})(key)
);
}
calls[0]('you');
calls[1]('me');
prints:
say: hello to you
say: howdy to me

I think what you want here is async.each
async.each(calls, function(key, cb) {
processAccounts(key, cb);
},
function(err){
if (err)
console.log('oh no!', err);
console.log('all accounts processed');
});

Related

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);

Generating functions for async waterfall with Map

I am trying to produce async function by iterating through the array of 'titles' and passing array of function later to async waterfall.
according to docs:
var asyncFunction = [
function(callback){
asyncFunc(1, function(){
callback(null);
});
},
// page 2
function(data, callback){
asyncFunc(2, function(){
callback(null, data);
});
}
]
The first function takes callback as the first parameter, while the second and all subsequent functions function is taking data as the first parameter and callback as the second.
My question how do I create function conditionally based on the index of map iteration?
Below is !non-working code example to give you an idea what I'm trying to accomplish.
Thanks
const asyncFuncs = ['a','b','c'].map( (letter, index) => {
const args = i == 0 ? [callback] : [data, callback]
return function(args...){
asyncFunc(2, function(){
callback(null, data);
});
}
})
async.waterfall(asyncFuncs, (error, result) => {})
Sorry if I was wrong.
I guess that you want to dynamic waterfall functions base on your data.
var yourData = ['a','b','c'];
async.map(yourData, yourAssignFunction, function (err, result) {
if(!err) {
console.log('Success: ' + result);
} else {
console.log('Error: ' + err);
}});
function yourAssignFunction(item, callback) {
if (item === 'a') { // your conditions check here
// use waterfall 1
callback(waterfallFunction1);
} else {
// use waterfall 2
callback(waterfallFunction2);
}
}
function waterfallFunction1(item, callback) {
async.waterfall([
function(cb){
console.log(' -> task1: ', item);
cb(null, item);
},
function(response,cb){
console.log(' -> task2: ', item);
cb(null, item);
}], callback)
}

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);
});

Converting to async.waterfall

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);
}
});
}

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