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.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I have one oDataModel and I am reading a particular property, with read function. When data read is success I am assigning it to a variable. But it is always saying undefined
readData : function(){
var oModel = this.getView().getModel();
var locationID;
oModel.read('/Locations',{
success: function(oData,oResponse){
console.log(oData.results[0].id); //This is printing the data in console, properly
locationID = oData.results[0].id;
}
});
console.log(locationID); //This is printing as undefined
}
read is asynchronous. When you do oModel.read, it essentially fires the request but doesn't block the executing thread. If you do a debug of the above code, you'll observe that execution goes to console.log(locationID); immediately after oModel.read. At this point, locationID is undefined (Since assignment hasn't happened yet). The assignment only happens after the callback function success is executed.
To solve this, you can wrap your oModel.read within a Promise. You need to resolve your promise inside success.
readData: function() {
var oModel = this.getView().getModel();
var locationID;
new Promise((resolve, reject) => {
oModel.read('/Locations', {
success: function (oData, oResponse) {
console.log(oData.results[0].id);
locationID = oData.results[0].id;
resolve(locationID)
},
failure: function (oError) {
reject(oError)
}
});
}).then(data => console.log(data))
}
I'm not 100% sure of the syntax, but this should help put you on the right path.
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();
}
});
This question already has answers here:
Javascript callback - how to return the result?
(3 answers)
Closed 8 years ago.
This is a noob JS question that I can't quite verbalize well enough to successfully Google.
function getUser(username){
var toReturn = { };
Restangular.one('users', username).get().then(function(result){
toReturn = result;
});
return toReturn //doesn't work
}
Restangular.one(...).get() initializes a REST call to get user data from the server. .then(...) is a callback that runs after data is returned. However, this getUser() function, as written, always returns an empty object, because it returns before the callback is triggered. How might I go about writing this function so that it returns the retrieved object?
(p.s. I know that this question is academic with regard to angular, since it handles promise resolutions transparently. I'm new to JS in general, and this is a general JS question).
Since server call is asynchronous, you should provide callback.
You can use promise or callback
Using Callback
function getUser(username, callback){
Restangular.one('users', username).get().then(function(result){
callback(result);
});
}
call: getUser('username', function(result){ /*do stuff here */ });
Using Promise
function getUser(username){
var callback;
var promise = {then: function(cb){
callback = cb;
}
};
Restangular.one('users', username).get().then(function(result){
callback(result);
});
return promise;
}
call: getUser('username').then(function(result){ /*do stuff here */ });)
Just try with:
function getUser(username, callback){
Restangular.one('users', username).get().then(callback);
}
getUser('hsz', function(result){
console.log(result);
});
The rest call is probably an async call. If you have control over the API, you can make a synchronous request which will then wait for it to return. Something like this:
function getUser(username){
var toReturn = { };
return Restangular.one('users', username).get().then(function(result){
return result;
});
}
It depends on how then is handled too. I'm assuming here that then() will return the result as well.
However, the best way in this scneario is to use a callback:
function getUser(username, callback) {
Restangular.one('users', username).get().then(callback);
}
Yes, that won't work because the problem is with your function. Every AJAX call is executed asynchronously, thus like the result.
If you have made an AJAX call like that, it will have to ask the browser to load that request, process the response and then execute the (function(result) { }) that you put as the last argument with the result.
So, you must change your function to have a callback too, like:
function getUser(username, onResultHandler){
Restangular.one('users', username).get().then(onResultHandler);
}
Then you can use it like this:
getUser('Daniel', function(user) { updateSomethingWithMyUser(user); });
Did you get it?
The simplest way, is to not overwrite the object you just created, because objects are passed around by reference.
For example:
var a = function() {
var b = {};
setTimeout(function() { b.a = 'hi'; }, 100);
return b;
}
b = a();
console.log(b); // Object {}
setTimeout(function() { console.log(b) }, 100); // Object {a: "hi"}
Because we simply set a property of the object, we are setting a property on the SAME object that got returned. When you do something like:
toReturn = result;
like in your function, you aren't changing the thing toReturn referenced, you are changing what toReturn references to (it used to reference to {}, now it references whatever result it).
So, in your case:
function getUser(username){
var toReturn = { };
Restangular.one('users', username).get().then(function(result){
toReturn.result = result;
});
return toReturn;
}
As soon as you get the result, toReturn.result will have it.
How might I go about writing this function so that it returns the retrieved object?
You can't, and you shouldn't. Restangular makes the call async so that your application can carry on running while waiting for a response.
If you want to make it look synchronous, I suggest the following approach (here's where its different from other answers):
function getUser(username){
return Restangular.one('users', username).get();
}
/* Usage */
getUser('username')
.then(function(result) {
/* do something with result */
});
I've got an app that works in most browsers. Unfortunately, with Internet Explorer 10 on Windows Phone 8, I'm very limited to what I can change. There are a few functions that don't work in WP IE10 - but I want to fix these by hijacking the functions, as opposed to rewriting any code.
var valueNeeded = myFunction("settings")
// This function cannot have another param without me having to change lots of code
myFunction = function (field) {
db.values('tblStorage', null, 10).done(function (results) {
return (results[i].value);
});
}
The problem I have is the database call isn't blocking/synchronous and so the return doesn't work. Normally I'd add a callback into the param, but as I want ONE codebase for all browsers, I can't really do that.
Any thoughts?
Asynchronous functions require the whole callstack to be asynchronous.
I would rewrite your code to this:
myFunction("settings").done(function (value) {
console.log("value", value);
});
myFunction = function (field) {
// v-- added return here v-- then here, so we return another promise (so we can call .done())
return db.values('tblStorage', null, 10).then(function (results) {
return (results[i].value);
});
}
So what does myFunction return? It returns a promise. The promise that, when it is resolved, it will have the value you requested.
To be more exact: myFunction returns the value of db.values(/**/).then(), which is a promise. db.values(/**/) also returns a promise. You can stack promises and chain them together to get a kind of asynchronous pipe-and-filter.
If you unchain the functions you'd get something like this:
myFunction = function (field) {
var value_promise = db.values('tblStorage', null, 10);
var filtered_value_promise = value_promise.then(function (results) {
return (results[i].value);
});
return filtered_value_promise;
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I have the following jQuery Function. I'm trying to return the GUID value shown here in the alert(); The alert works fine and the value is populated, however I can't seem to assign it to a variable and return its value.
Ultimately I need to access the GUID value in other functions, etc. Everything I've tried only displays as undefined.
I'd like to do something like this:
function trackPage(){
var elqTracker = new jQuery.elq(459);
elqTracker.pageTrack({
success: function() {
elqTracker.getGUID(function(guid) {
alert(guid);
var returnValue = guid;
});
}
});
return returnValue;
}
var someGuid = trackPage();
So, this question has been asked a million times over, and I'm sure that everyone (myself included) tried this once.
It is just the nature of an asynchronous call, you can't use their results as a return value. Thats why they have you passing in a function that gets the result of the call, they can't return it either! Also notice that the elqTracker.pageTrack() function call returns IMMEDIATELY, therefore your returnValue is simply undefined.
Most people (see dfsq's answer) solve this problem by introducing a callback function as a paramater. This method is tried, and true – however jQuery has $.Deferred. This allows you to make your own asynchronous logic return a promise which you can then attach any number of callbacks to:
function trackPage(){
var elqTracker = new jQuery.elq( 459 ),
dfd = $.Deferred();
elqTracker.pageTrack({
success: function() {
elqTracker.getGUID(function( guid ) {
dfd.resolve( guid );
});
}
});
return dfd.promise();
}
// example use:
trackPage().done(function( guid ) {
alert( "Got GUID:" + guid );
});
Notice now that your trackPage() returns an object that you can attach callbacks to? You don't have to attach them immediately either.
var pageHit = trackPage().done(function( guid ) {
alert( "Page Hit GUID:" +guid );
});
$("button").click(function() {
pageHit.done( function( guid ) {
alert( "Clicked on Page GUID:" + guid );
});
});
Also, the jQuery AJAX module always returns promises as well, so the interface for all your AJAX stuff should be very similar if you make your own logic return promises.
As a side note: I'd like to point out that your var returnValue was in the wrong "scope" anyway. It needed to be declared in the outer scope of the trackPage function. Even with this fix, the concept still doesn't work.
Since you have asynchronous call the way you are trying to write code is not going to work (because by the moment of return returnValue; in the trackCode return value is not yet defined). Instead you should pass callback into trackPage:
function trackPage(callback) {
var elqTracker = new jQuery.elq(459);
elqTracker.pageTrack({
success: function() {
elqTracker.getGUID(function(guid) {
alert(guid);
// Instead of this: var returnValue = guid;
// You should use your callback function
callback(guid);
});
}
});
return returnValue;
}
trackCode(function(guid) {
// perform some actions with guid
});