This question already has answers here:
AngularJS : Where to use promises?
(4 answers)
Closed 7 years ago.
I have the following code:
//calling AsyncFunction
var coords = LocationSerivice.getLocation();
var localStores;
setTimeout(function(){
//works
console.log(coords);
//calling async function again
localStores = LocalStoresService.getLocalStores(coords[0],coords[1]);
}, 100);
setTimeout(function(){
//doesn't work
console.log(localStores);
}, 100);
What am I trying to do is to first call a Async function that returns my location. Then in order to get the data from that function I am setting timeout. With the data received I am calling second Async function. And again I am setting timeout in order to get the data from my second Async function, so here it fails. If I try to display the data with console.log() in the timeout block it says undefined while console.log()in the first timeout block works.
I have tried also increasing the timeout time but it just doesn't work.
Any suggestions how to get over that ?
You could modify your LocalStoresService.getLocalStores method to accept a callback.
function getLocalStores (arg1, arg2, cb) {
// do stuff.
var localStores = 'w/e';
if (typeof cb === 'function') return cb(localStores);
}
So your invoking method would look like this:
var coords = LocationService.getLocation();
LocalStoresService.getLocalStores(coords[0], coords[1], function (localStores) {
console.log(localStores); // 'w/e'
});
It really depends on the type of technology you're using, as the "correct" implementation of async methods can vary from type to type (AngularJS, NodeJS, vanilla JS etc..)
As i understand your project might be using angularjs i am giving example based on that ,
.factory('LocationSerivice', function ($http) {
return{
getLocation : function () {
return $http.get('location_api');
};
getLocalStores : function(coords){
return $http.get('your_local_store_api');
};
}
});
Now call your API's
LocationService.getLocation().success(function(coords){
LocationService.getLocalStores(coords).success(function(localStores){
console.log(localStores);
});
});
Related
This question already has answers here:
setTimeout - callback argument must be a function
(4 answers)
Closed 3 years ago.
I want to make a loop that downloads a file on an interval. But I can't make the setTimeout function work when the request function needs a parameter. It's the last line of the progam that i failing. What am I doing wrong?
const http = require('http');
const fs = require('fs');
const file = fs.createWriteStream("file.jpg");
const fileToDownload = "http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg";
function request1() {
http.get(fileToDownload, function(response) {
response.pipe(file)
});
}
function request2(saveName) {
const save = fs.createWriteStream(saveName);
http.get(fileToDownload, function(response) {
response.pipe(save)
});
}
setTimeout(request1, 3000);
setTimeout(request2("file2.jpg"), 3000); // TypeError: "callback" argument must be a function
You're not passing a function, rather its result.
Use the following instead:
setTimeout(() => request2("file2.jpg"), 3000);
Instead of passing a function to the setTimeout as it expects, you're passing a function call, which will take the parameter as the return type of the function instead of the function itself.
Instead you can just pass a function like -
setTimeout(() => request2("file2.jpg"), 3000);
Instead of calling function directly, try this:
setTimeout(function(){
request2("file2.jpg")
}, 3000);
Or using arrow function
setTimeout(() => request2("file2.jpg"), 3000)
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I have a module like this.
somemodule.js
module.exports = {
val: null,
get: function() {
finddata('/', function(resp) {
this.val = resp
}
}
}
and is called like this:
var x = require('somemodule');
x.get();
x.get();
After the 1st get call, this x.val is not being set. Tried this as well which does not work:
module.exports = {
val: null,
get: function() {
var that = this;
finddata('/', function(resp) {
that.val = resp
}
}
}
How do I set x.val?
Your finddata is running asynchronously , it's getting called and returned back immediately to continue next line execution . That moment its not sure callback is executed or not . Once callback is executed then only value will be set . To make sure value is set and then after getting the value , you can use promises.
I have just taken two sample file a.js and b.js to explain how it works
a.js
module.exports = {
val:null,
get:function(){
var that = this;
return new Promise(function(resolve, reject) {
that.finddata('/', function(resp){
that.val = resp;
resolve()
})
});
},
finddata :function(path,callback){
setTimeout(function() {
console.log("Lets wait for some time");
callback(10);
}, 100)
}
}
b.js
var x = require('./a');
x.get().then(function(){
console.log(x.val)
});
Output
Lets wait for some time
10
First of all, problem is not about requiring something and it is not related to scope. What is actually happening is, as already stated by others, finddata is asynchronous function meaning that you don't know at what time in future callback function (resp) {...} will be invoked and when val be something other than null. To tackle this you need either to pass additional callback to get function, or to return a promise from get function. Cleaner approach would be to return Promise from get function.
x.get()
.then(() => {
// val is ready
})
or
x.get(() => {
// val is ready
})
Another problem that you have is that you are not taking into account what if finddata invokes your callback with an error? Having something like:
finddata('/', function(resp){
that.val = resp
}
Is really something what you don't want to have. With code that you have, if finddata invokes your callback with an error, val would be equal to that error, otherwise it would be equal to null, if finddata complies to node best practices to invoke callback with null if there was no errors, such as cb(null, data).
Besides that what you are trying to do? Is there a need for exposing module with val thing? Is get function meant to be called regularly from app? If so why introducing new module, just call finddata which is i guess module by itself already.
I set up a callback function inside my Meteor async method to be called on "readable" event. But the callback is not being called when the on."readable" is being fired (I know it's being fired from the console.log I set up).
Am I missing something here? I've been at it for a few hours now trying a few different things!
Meteor.startup(() => {
Meteor.call("getfeed", function(feedloader) {
//I get: TypeError: undefined is not a function]
console.log(feedloader);
});
});
Meteor.methods({
getfeed: function(callb) {
var req = request('http://feeds.feedburner.com/Techcrunch');
var feedparser = new FeedParser();
testing = [];
//........a bunch of functions........
feedparser.on('readable', function() {
var stream = this
, meta = this.meta
, item;
while (item = stream.read())
{
//I'm pushing the results into testing var
testing.push(item);
}
//From the logs I can see that this is called 12 times
//but the callback's not firing!!!
console.log(testing.length);
callb(testing);
});
}
});
Meteor methods are not asynchronous functions in the sense that they do not get the callback argument even though you pass it when you "call" a method. Instead each method is executed within a Fiber which is another flavor of dealing with asynchronous code.
Fortunately, Meteor has a nice helper that allows you to mix both styles. What you need to do is wrap the "pure" asynchronous part of your method code with Meteor.wrapAsync. This structure should look more or less like this:
Meteor.methods({
getfeed: function() {
var wrapped = Meteor.wrapAsync(function (callb) {
var feedparser = new FeedParser();
testing = [];
// ...
feedparser.on('readable', function() {
// probably the same code you have, but without "callb()"
});
feedparser.on('end', function () {
// NOTE: No error here, so the first argument must be null.
callb(null, testing);
})
});
// NOTE: Finally, call the wrapped function
return wrapped();
}
});
I´ve been making a prototype of webservice and I get confronted with the following problem: Whenever I try to use a 'var' as a callback i get: undefined.
What I'm tryng to do is:
var mysqlquery = function (){
var vAlue = XXX;
}
var service = function (pp, ee, cb){
var toReturn= ({ //XML code
Value: vAlue
})
cb(toReturn);
};
Output should be XXX
The service runs fine and logs the values, but when i try to make it a callback to respond it is undefined, I guess because of the async of node.
Already tried making it a global or global.window or calling it inside another function, none of wich work. I don´t want to use extra modules for this, is there any method for it ? (Also tried this.)
Any tip is much apreciated, thanks.
You already know that defining a var in a function limits its scope to that function, but you can pass that data out of the function using a return, like so:
var mysqlquery = function (){
return 'XXX';
}
console.log(mysqlquery())
> "XXX"
What's happening in the console.log line is that your function is being evaluated, and returns "XXX", and then it is passed to console.log.
This is the foundation of callbacks: if you have an asynchronous function, you can pass a callback function into it to feed in the result of the async function:
function print(res) {
console.log(res)
}
function asyncThing(cb) {
var ten = 5 + 5
window.setTimeout(cb.bind(this, ten), 5000)
}
asyncThing(print)
... [wait five seconds]...
> 10
I want to understand one thing about async module in node.js.
I have created a function that map an object from a form to a model object and return this object.
This object is a video with an array of tags.
My question is where can I return the video ? I know normally it is inside the async callback function but if I do that, the object returned is undefined.
Whereas If i return the video object at the end of the whole function, it works but it's not safe as I'm not sure, my async is finished...
By the way, I don't understand the callback function passed in argument to async.each and
called after video.products.push(tag); . What does this function do?
Regards
in my mapping.js :
exports.video = function(object) {
var video = new Video();
video.name = object.name;
video.products = [];
async.each(object.tags, function(tago, callback) {
tag = {
"name" : tago.name
}
video.products.push(tag);
callback();
} ,
function(err) {
if( err ) {
console.log('Error' + error);
throw err;
}
logger.debug("into async" + video);
}
);
logger.debug("end function " );
**//return video;**
}
in my video.js :
var video = mapping.video(object);
logger.debug(video); // return undefined
The simple answer is that you can't - at least not via easy or obvious approach. As its name suggests, async is a library for queuing up asynchronous function calls into the event loop. So your exports.video function simply kicks off a bunch of asynchronous functions, which execute one after the other on an unpredictable time-frame, and then returns immediately. No matter where you try to return your video object within the scope of your function calls which are instantiated by async, the exports.video function will already have returned.
In this case it doesn't really seem like you need asynchronous function calls for what you're doing. I'd suggest that you replace your use of async with something like Underscore's each method, which executes synchronously, instead.
http://documentcloud.github.io/underscore/#each
You'd need to define a callback for your exports.video function e.g..
exports.video = function(object, callback) {
// video code (snip)...
async.each(object.tags,
function eachTag(tag, done) {
// code run for each tag object (snip)...
done();
},
function finished(err) {
// code run at the end (snip)...
callback(thingThatsReturned);
});
};
...and call it like this:
var videoUtils = require('videoUtils');
var tags = getTags();
videoUtils.video({ tags: tags }, function(thingThatsReturned) {
// do something with 'thingThatsReturned'
});
By the way, I don't understand the callback function passed in
argument to async.each and called after video.products.push(tag); .
What does this function do?
The async.each function will call the 'eachTag' function above (2nd argument) for each item in your array. But because it's done asynchronously, and you might do something else async in the function (hit a database/api etc.), it needs to know when that function for that particular array item has finished. Calling done() tells async.each that the function has finished processing. Once all the functions are finished processing (they've all called done()), async.each will run the 'finished' function above (3rd argument).
This is pretty standard async stuff for Node.js, but it can be tricky to get ones head around it at first. Hang in there :-)
Edit: It looks like your code isn't doing anything asynchronous. If it was, then the above code would be the way to do it, otherwise the following code would work better:
exports.video = function(object) {
// video code (snip)...
if (Array.isArray(object.tags)) {
object.tags.forEach(function eachTag(tag) {
// code run for each tag object (snip)...
});
}
return thingThatsReturned;
};
...and call it...
var videoUtils = require('videoUtils');
var tags = getTags();
var thingThatsReturned = videoUtils.video({ tags: tags });