Code only works when I place a breakpoint - google-chrome-extension

I got the following code (in a seperate file called page.js):
var page = new function() {
this.getImdbID = function(){
var imdbid = '';
chrome.tabs.getSelected(null, function(tab) {
imdbid='0944835';
});
return imdbid;
};
}
Which gets called by the following code (which is in background.html).
var imdbid = page.getImdbID();
This code only works when I place a breakpoint on the "return imdbid;" row. When I skip the breakpoint it only returns an empty string. Is there anything I have missed?

The fact that it works when you place a breakpoint suggests a timing issue.
In this case, I would suppose that getSelected is an asynchronous operation (hence why it takes a callback), and so you would need to wait for it to complete and the callback to be executed before the variable has the value you want.

Related

Nodejs Callback: How to define a Callback?

I am reviewing a sample nodejs server code, which is working fine. but could not understand the following code:
var handlers = {};
// Creating a sample handler
handlers.sample = function(data,callback){
callback(406,{'name':'sample handler'}); // How is this line of code working??
};
// Creating a not found handler
handlers.notFound = function(data,callback){
callback(404); // How is this line of code working??
};
In the entire code there is no implementation of "callback" function then how
callback(406,{'name':'sample handler'});
and
callback(404);
are working?
Please suggest. Thanks.
callback isn't implemented in the code you posted; it's a named parameter.
To call one of the functions that requires a callback, you'll need to pass it in as an argument, like:
handlers.sample("some data", () => console.log("I'm in a callback!));
The first argument ("some data") goes in the data parameter, and the second argument (() => console.log("I'm in a callback!)) goes in the callback parameter. When callback(404) is run, it executes the callback function (in the above example, it would do console.log("I'm in a callback!)).
Basically, when you call handlers.sample, you should pass a function as your second argument, and that function will be called, usually asynchronously, and presumably after something is done with the data you pass as the first argument. For example, based on the code you provided:
handlers.sample(dataObject, (number, object) => {
console.log(number)
console.log(object.name)
})
would yield this result in the console:
406
sample handler
I’m curious if this is a public library you are seeing this code in, so we can take a closer look?
I did a further digging in into this and found that
selectedHandler
in the following code (this is not mentioned in the question) is getting resolved into handlers.sample or handlers.notFound variable names based on some logic (which is not mentioned here)
selectedHandler(data,function(status,payloadData){
// somelogic with the status and payloadData
});
And second parameter of this function which is a complete function in itself
function(status,payloadData){
// somelogic with the status and payloadData
}
is going as the second parameter in handlers.sample or handlers.notFound which is a Callback. So execution of Callback in the current context is execution of this function (this function is anonymous because it has no name and getting executed as Callback)

How to test socket.io events being called with sinon.spy

First of all, I'm trying to test the second time a function being called returns the correct value. To be more specific, I'm trying to test the second time an event is received by socket.on() returns the correct value.
I know that Sinon.spy() can detect whether a function being called or not. But it seems not working with socket.io events.
I'm trying to test for example,
var socketio = io.connect(someUrl);
socketio.on(eventName, cb);
if the 'eventName' is called. I tried
var spy = sinon.spy(socketio, 'on');
assert(spy.withArgs(eventName).called);
But it says it's never being called.
Furthermore, what if I'd like to test the data in the callback function is right or not, for example
var socketio = io.connect(someUrl);
socketio.on(eventName, function(data) {
data.should.equal(something);
});
Is it possible to test that?
Update:
I solved the problem by adding a count in callback
var count = 0;
socketio.on(eventName, function(data) {
count++;
if(count === 2) {
data.should.equal(something)
}
}
But I think this is a hacky way, is there any standard/smart way to do it(if possible using sinon)?
You don't want to spy on on -- that's only called once, at the time you set up the listener. (Unless you actually want to spy to see if the listeners are being set up at all, and don't care if they're actually used. That doesn't appear to be what you want here.)
Instead, you want to spy on the cb callback function, to see if and how it runs.
var callbackSpy = sinon.spy(cb);
Then, pass that spy in as the callback:
socketio.on(eventName, callbackSpy);
And test if the callback was ever run with the desired argument value:
assert(callbackSpy.calledWith(something));

IntelliJ NodeJS Debugging Callback Scope Reference Error

I'm debugging a NodeJS application in Intellij. I have a method that looks as follows:
function(connection) {
connection.on('error', function(error) {
console.log('there is an error'); // breakpoint is on this line
});
}
When the breakpoint is hit, connection is not defined, and putting connection in the Evaluate Expression window yields "ReferenceError: connection is not defined."
It appears to me that connection is being deallocated because it's not being used within the callback, but I'm debugging the application, so how can I make it not be deallocated, short of adding the line localConnection = connection (which does work).
Here's another example:
var foo = (function() {
var a = 'some value';
this.bar = function() {
console.log('bar'); // breakpoint is here
};
this.bar();
})();
Here, a is inaccessible from the debugger.
EDIT:
To clarify the second example, a is private to methods declared outside of foo, but not otherwise. Case in point:
var foo = (function() {
var a = 'Some value';
this.bar = function() {
console.log('a: ' + a); // breakpoint is here
};
this.bar();
})();
This example does print "a: Some value," suggesting that a should be accessible within the line. And as a matter of fact, simply by adding it in the console log, it does stay accessible in that line, which suggests that its previous inaccessibility was due to garbage collection or reference counting, which, in a debugging environment, I would like to be less rigorous, because I would like to maintain the ability to see the values of variables that are not necessarily used in code at debug-time.
The same applies to the first example. When using connection inside the callback in code, it's exposed to the debugger, but I'm trying to make it stay exposed even without code usage. How do I do that? I'm quite positive there is a runtime flag for Node to accomplish that.
First example, connection is an event emitter. so the outer function has already been finished to work when "error" event occurs. So you can not get it back. second example is an IIFE and "a" is somewhat a private variable even if does not look like that way.
You can use a global variable to access both of them. I know this looks like a dirty workaround. but it works anyway, here is an example:
var m;
function(connection) {
m = connection;
connection.on('error', function(error) {
console.log('there is an error'); // breakpoint is on this line
console.log(m); // now you can access connection
});
}

Returned method call is undefined?

Ok so i am using a method to make a request and pull some tables from another URL
Meteor.methods({
gimmetitle: function () {
var url = 'http://wiki.warthunder.com/index.php?title=B-17G_Flying_Fortress';
request(url, function(err, response, body) {
$ = cheerio.load(body);
var text = $('.flight-parameters td').text();
console.log(text);
return text;
});
}
});
When called the td's in the table succesfully print to the server console: http://prntscr.com/721pjh
Buuut, when that text is returned from that method to this client code, undefined is printed to the console:
Template.title.events({
'click #thebutton': function () {
Meteor.call('gimmetitle', function(error, result){
Session.set('gogle', result);
});
var avar = Session.get('gogle');
console.log(avar);
}
});
Ideas?
You need to understand two different things here :
On the client side, making some calls to the server is always asynchronous, because we have to deal with network latency. That's why we use callbacks to fetch the result of Meteor methods : this code is executed some time in the future, not right away.
This is why Session.set('gogle', result); is actually executed AFTER var avar = Session.get('gogle'); even though it appears before in your event handler code flow.
Contrary to template helpers, event handlers are NOT reactive, so it means that when you set the Session variable to the result of the method, the event handler code is not automatically reexecuted with the new value of Session.get('gogle').
You'll need to either do something with the result right in the Meteor method callback, or use a reactive computation (template helpers or Tracker.autorun) depending on Session.get('gogle') to rerun whenever the reactive data source is modified, and use the new value fetched from the server and assigned to the Session variable.
Quick update..Was able to fix this with just 1 line of code lol.
instead of request(url, function(err, response, body) i used the froatsnook:request package and used var result = request.getSync(url, {encoding: null}); and then just replaced $ = cheerio.load(body); with $ = cheerio.load(result.body);.

this.async() in yeoman-generator

I am learning how to write a yeoman-generator. I have a question regarding the code below. It says by adding var done = this.async(); and call the method later in callback, we can make the function askFor() a asynchronized function. Could someone please explain why?
askFor: function() {
var done = this.async();
// Have Yeoman greet the user.
this.log(yosay('Welcome to the marvelous Myblog generator!'));
var prompts = [{
name: 'blogName',
message: 'What do you want to call your blog?',
default: 'myblog'
}];
this.prompt(prompts, function(props) {
this.blogName = props.blogName;
done();
}.bind(this));
}
Here is the code of this.async
this.async = function() {
return function() {};
}
Just fell on this question by pure coincidence searching for something else.
Actually, this.async is overwritten on each method during the run phase to either delay execution until completion or run synchronously.
You can read the relevant code line here:
https://github.com/yeoman/generator/blob/master/lib/base.js#L372-L393
So basically, behind the scenes Yeoman always call a callback. When you call this.async() we keep a reference variable and return the callback. If you don't call it, we take care of calling the callback manually after the function end.

Resources