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();
}
});
Related
in my chrome extension I need to use chrome storage. In my background script first I create an object and add it to chrome storage and then I want to get my object from there and to be returned. Something like that:
...
var obj = {};
chrome.storage.local.set(obj, function () { });
...
var data = getData(obj); // I want my object to be returned here
var returnedData = null;
function getData(obj) {
chrome.storage.local.get(obj, function(result) {
returnedData = result; // here it works, I can do something with my object
});
return returnedData; // here it doesn't work
}
As far as I understood from here chrome.storage.local.get is asynchronous with its consequences. But is there any way how to get something from chrome storage and make it to be returned? I mean maybe I should wrap chrome.storage.local.get in another function or so?
Many thanks in advance!
If you want to stay away from global variables and you're okay with modern browser requirements, then you can implement a native JavaScript Promise object. For example, here's a function that returns the stored data for a single given key:
function getData(sKey) {
return new Promise(function(resolve, reject) {
chrome.storage.local.get(sKey, function(items) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
reject(chrome.runtime.lastError.message);
} else {
resolve(items[sKey]);
}
});
});
}
// Sample usage given this data:
// { foo: 'bar' }
getData('foo').then(function(item) {
// Returns "bar"
console.log(item);
});
If you need support for IE11 and below, then you'll have to turn to a library like jQuery.
No it's not possible
But there are several ways around this problem
Do everything you want to do with the data returned from .get() inside the callback (or start it from there using function calls). This is what #wernersbacher posted
Take a look at deferreds (jQuery or Q libraries). A deferred's promise can be returned from getData. Inside the .get() callback, you can resolve the deferred. Outside of getData you can use .then() to do something after the deferred resolved
Something like this
function getData(obj) {
var deferred = $.Deferred();
chrome.storage.local.get(obj, function(result) {
deferred.resolve(result);
});
return deferred.promise();
}
$.when(getData(obj)).then(function(data) {
// data has value of result now
};
You have to do it like that:
var returnedData = null;
function setData(value) {
returnedData = value;
}
function getData(obj) {
chrome.storage.local.get(obj, function(result) {
setData(result); // here it works, I can do something with my object
});
return; // here it doesn't work
}
..because you tried to return a value which did not get read from storage yet, so it's null.
Update with Manifest V3 :
Now chrome.storage.local.get() function returns a promise that you can chain or can await in an async function.
const storageCache = { count: 0 };
// Asynchronously retrieve data from storage.local, then cache it.
const initStorageCache = chrome.storage.local.get().then((items) => {
// Copy the data retrieved from storage into storageCache.
Object.assign(storageCache, items);
});
Note : You must omit the callback paramter to get the promise.
Reference : https://developer.chrome.com/docs/extensions/reference/storage/#:~:text=to%20callback.-,get,-function
You need to handle it with callback functions. Here are two examples. You use a single function to set, however you create a separate function for each "On Complete". You could easily modify your callback to pass additional params all the way through to perform your needed task.
function setLocalStorage(key, val) {
var obj = {};
obj[key] = val;
chrome.storage.local.set(obj, function() {
console.log('Set: '+key+'='+obj[key]);
});
}
function getLocalStorage(key, callback) {
chrome.storage.local.get(key, function(items) {
callback(key, items[key]);
});
}
setLocalStorage('myFirstKeyName', 'My Keys Value Is FIRST!');
setLocalStorage('mySecondKeyName', 'My Keys Value Is SECOND!');
getLocalStorage('myFirstKeyName', CallbackA);
getLocalStorage('mySecondKeyName', CallbackB);
// Here are a couple example callback
// functions that get executed on the
// key/val being retrieved.
function CallbackA(key, val) {
console.log('Fired In CallbackA: '+key+'='+val);
}
function CallbackB(key, val) {
console.log('Fired In CallbackA: '+key+'='+val);
}
I'm trying to solve a JavaScript challenge where I have to use asynchronous callbacks.
Here is what the challenge says:
Define a function named doStuffAsync that takes one argument callback. Your function should read the contents of file "passwords", write the result to file "world.txt" along with the extra text "OWNED", then call callback with no arguments. Use both the asynchronous readAsync and asynchronous writeAsync.
My code is as follows:
var files = { "passwords": "abc,def",
"world.txt": "hello" };
var readAsync = function(file, callback) {
callback(files[file]);
};
var writeAsync = function (file, contents, callback) {
files[file] = contents;
callback();
};
var test = function() {
files["out.txt"] = "final";
files["passwords"] = "blank";
};
//this is the part I'm interested in
var doStuffAsync = function (callback) {
var contents = 0;
contents = readAsync("passwords");
writeAsync("world.txt", contents, callback());
};
Here is the link to the challenge http://nathansjslessons.appspot.com/lesson?id=1085
The most straightforward way to accomplish this using just callbacks is by nesting the function calls like this:
function doStuffAsync(callback) {
readAsync("passwords", function(contents) {
writeAsync("world.txt", contents + "OWNED", function() {
callback();
});
});
}
In this case, since your callback function doesn't require any arguments, you can save one level of nesting and just do this:
function doStuffAsync(callback) {
readAsync("passwords", function(contents) {
writeAsync("world.txt", contents + "OWNED", callback);
});
}
This isn't so bad with just two callback actions, but it can quickly get pretty messy when you need to perform a lot of asynchronous steps in sequence. Promises are one mechanism that were devised to help manage this problem, and I recommend checking them out.
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 });
In JavaScript I want to override a function on an object, but still call the original function and return it's value. So I'd normally do something like this:
var render = res.render;
res.render = function() {
doSomethingNew();
return render.apply(this, arguments);
};
However, what if that override contains async callbacks that need to be fired first before calling the original function eg:
var render = res.render;
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
function callNextMiddleware(middlewares, callback) {
var middlewareFunc = middlewares.shift();
if (middlewareFunc) {
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
}
else {
return callback();
}
}
Notice that I'm using a 'return' statement where required. I have one problem though, the 'middlewares' variable is an array of functions, each middleware function looks like this:
function myMiddleware(next) {
performLongRunningAsyncDataAccess(function() {
next();
});
}
Because it doesn't use 'return next()' the return value of the original res.render method is never passed back. I can get this to work if I get all the middleware functions to use 'return next()', but they come from an external source so I have no control over them, I can only guarantee that they will call 'next()'.
A bit of background, this is a Node.js app. The middleware is basically Connect middleware, and I'm trying to override the Express.js res.render method.
Generally it is a bad idea to mix asynchronous functions with return statements. Everything that you want to return, you can pass as arguments to your callback functions. So I still hope I understand your code correctly but I would assume, that you call the render function, which then grabs an array of middleware functions. Then you want to execute all the functions in that array, using the next as an callback to the previous. After all the functions have been executed, the render function should be called again, thus creating kind of an infinite loop. Assuming all of that, lets take a look at some of your return statements:
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
The first return in this block is useless since middlewareFunc is asynchronous and will therefore most likely return undefined. The second return statement is also useless, since it returns from the function, that you use as callback. But since your callback is just called by using next();, the return value will never be used.
else {
return callback();
}
In this block callback is the render function. So lets take a look at this function:
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
So all last three return statements are essentially there, because you want to return something from your render function. But to be consistent, you should consider using a callback for that function as well:
res.render = function(callback) {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
callNextMiddleware(middlewares, function() {
//this will be called after all the middleware function have been executed
callback();
render.apply(self, args);
});
};
So basically you are getting rid of all the return statements and using pure asynchronous design patterns.
callNextMiddleware should return its recursive call's return value, not middlewareFunc's.
if (middlewareFunc) {
var result;
middlewareFunc.call(this, function() {
result = callNextMiddleware(middlewares, callback);
});
return result;
}
Fiddle: http://jsfiddle.net/mWGXs
I'm relatively new to JavaScript and repeatedly find myself writing methods in a helper object which take in a callback as a parameter e.g.
var utilities = {
getTweets: function (user, maxTweets, callBack) {
var obj = $(this);
$.getJSON('http://api.twitter.com/1/statuses/user_timeline.json?callback=?&screen_name=' + user + "&count=" + maxTweets, function (data) {
callBack(data);
});
};
I then call it like so:
utilities.getTweets("TESTUSER", 4, function (tweets) {
.....
});
Given I am calling the code above using setInterval is this likely to leak over time/is there a better way to write this?
What you're doing is mostly fine, except that there's no need to create the extra closure. Passing a closure written like:
function (data) {
callBack(data);
}
is just the same as passing callBack directly in the parameter list.
However if you can guarantee running with jQuery 1.5 or later, then a better method is to just have getTweets() return the JQXHR object, and then you can use "deferred" methods in the client code:
var utilities = {
getTweets: function (user, maxTweets) {
var uri = 'http://api.twitter.com/1/statuses/user_timeline.json?callback=?';
var data = {
screen_name: user,
count: maxTweets
};
return $.getJSON(uri, data);
});
};
and then in the client code:
utilities.getTweets(user, maxTweets).done( /* your callback here */ );
In this way you can completely decouple the callback from the implementation. Indeed you can register multiple callbacks, and error handlers, all without touching the implementation of utilities.
NB: use of a map for data above also protects your code against parameter injection.
If you're afraid of the memory overhead of creating that function every time, then do something like:
utilities.getTweets("TESTUSER", 4, utilities.handleTweets);
And in utilities.handleTweets you do as you do in the callback.
You could use something like this:
var utilities = {
options: {
user: 'value',
maxTweets: '4'
}
getTweets: function() {
// access a value
this.options.user;
}
}
Or it would be best to create a proper plugin with options etc. Have a read of this article, it should be exactly what you need:
http://jquery-howto.blogspot.com/2009/01/how-to-set-default-settings-in-your.html