Get parameters out of callback function - javascript

I have a function that looks like this:
main.add = function(){
var newTabId;
chrome.tabs.create({"url":"enter.html","active":true},
function(tab) {
newTabId = tab.id;
}
);
console.log(newTabId);
}
But when newTabId is printed to console the chrome.tabs.create function hasn't run so the var is undefined.
Is there any way to ensure the code from the chrome namespace finishes before running anything below it?

First, do newTabId global, defining it outside the function. Your two "newTabId" belong to different namespaces.
Secondo, the function inside chrome.tabs.create will start after your main code finish. It's asynchronous programming. chrome API is all asynchronous, so, get used to it, there's no workaround, sadly.
If you want to start thinking asynchronous, I recommend using promise with jQuery's deferred.

Related

How to call an external function from within casper.start or casper.thenOpen

I am trying to split the following code such that the callback function which is stored in its own file.
var casper = require('casper').create();
casper.start("http://www.google.com/", function() {
this.echo(this.getTitle());
});
casper.run(); // "Returns Google"
Following this example, I define a function in a separate file called "getPageTitle.js";
function getPageTitle(casper) {
casper.echo(casper.getTitle());
}
exports.getPageTitle = getPageTitle;
and call the function in another file called "main.js" by passing the CasperJS object into the function directly;
var casper = require('casper').create();
var casperFunctions = require('./getPageTitle.js');
casper.start("http://www.google.com/", casperFunctions.getPageTitle(casper));
# Error: CasperError: Casper is not started, can't execute `getTitle()`
Further, if I replace the last line in the above with a thenOpen() call;
casper.start();
casper.thenOpen("http://www.google.com/", casperFunctions.getPageTitle(casper));
The above code does not throw errors; CasperJS is able to navigate to the website, but the page title "Google" is not returned.
Could someone please shed light on why this doesn't behave as I expect. This seems like a natural way to modularize functions that CasperJS would call once pages are loading, but am I missing something here?
The execution of CasperJS is asynchronous. start() and all then*() and wait*() functions are asynchronous step functions. That means that you're only on the page inside of such as step.
When you look at your getPageTitle() and how it is called, you should notice that you're not passing a step function into casper.start(), but instead you're immediately calling getPageTitle(). At that time, the execution hasn't even begun, because the scheduled steps begin executing as soon as run() is called. By calling getPageTitle(), you're trying to access the title of about:blank which is blank.
First version:
function getPageTitle(casper) {
return function(){
casper.echo(casper.getTitle());
};
}
Now you're passing a step function into start() which will be evaluated asynchronously.
Second version:
Keep in mind that you can use this inside of a step function to refer to casper. This is a better way to do this, because you don't need to pass the reference explicitly:
function getPageTitle() {
return function(){
this.echo(this.getTitle());
};
}
and call it like this:
casper.start("http://www.google.com/", casperFunctions.getPageTitle());
Third version:
If you the function doesn't need any arguments, then you don't need a wrapper function. You can pass it directly:
function getPageTitle() {
this.echo(this.getTitle());
}
and call it like this:
casper.start("http://www.google.com/", casperFunctions.getPageTitle);
casper.start("http://www.google.com/", casperFunctions.getPageTitle(casper));
doesn't work, because you're passing the result of calling casperFunctions.getPageTitle(casper) as the callback parameter to casper.start
I think you should be able to do this instead
casper.start("http://www.google.com/", casperFunctions.getPageTitle.bind(casper));

Making requirejs wait until files have loaded before continuing

Is there a way to block javascript until requirejs has loaded the files?
I thought doing the following would work because I don't have a callback.
var requireFile = require(['example']);
but it is still asynchronous.
If I do have a callback specified is there a way to block until example is loaded, then execute the callback.
For example.
require(['example'], function(){
console.log('hello');
});
console.log('world');
Console should therefore be:
-hello
-world
I am seeing
-world
-hello
You can wrap the code you want to delay in a function, then call that function from the require callback.
require(['example'], function(){
console.log('hello');
world();
});
function world() {
console.log('world');
}
You can't block until it returns. But you usually don't have to.
You probably have some code that depends on the return from 'require', that code needs to go in the callback (or get called from inside the callback)
It can be a problem when you already have a bunch of code but its the only way to do it.
Sometimes you can have the other code not run until it sees that something it needs has loaded.
Sometimes you can just skip it running and it will get invoked later. Sometimes you have to set up a timer that keeps looking for that 'something' and then pausing a bit if not.

Implement a callback with a function that doesn't accept a callback?

This is a newbie question: I have a pre-existing function that I would like to have call another function when it is finished, however, it does not accept a callback nor of course call one. I can modify this code to accept and call a function however this got me thinking about whether JavaScript supports doing this ... I would think it does but I've never had reason to find this out, I'm assuming it's necessary when working with libraries where we cannot change the code to our liking. Thanks.
The only time you need a callback is when you are doing something asynchronous, such as:
making an HTTP request (and waiting for a response)
animating something, one frame every time period until it is done
waiting for the user to click a button
All of these are considered "done" when something happens, but there is no generic way to determine when the something has happened. You need something custom for each one.
If you aren't waiting for something, then you can just call one function after the other (foo();bar();) and not need to fiddle around with callbacks.
So…
It might be possible to do what you want, but we can't tell you a generic way to achieve it.
This is a bit of a hack, and i'm sure there's tidier ways to do this with polymorphism, but you can treat the function as a variable and re-assign it somewhat:
Say you start with this function:
function originalFunctionName()
{
// do something
}
you can assign the existing function to a new name:
var backupOfOriginal = originalFunction;
then you can define a new function over the original name:
var originalFunctionName = function()
{
// do something else
// call backup function
backupOfOriginal();
}
then if you call the original function name:
originalFunctionName();
all the code will execute.
You can always create a new function which calls that function and provides you with opportunities to do something else before and after it is called. Underscore.js provides .wrap() to do exactly that sort of thing and return you a function you can call instead of the first function.
That just gives you a new function to call instead of your original function, if you want every spot that called the original function to get the new behavior instead, you could take advantage of JavaScript's prototypal inheritance to replace the original function with your new version of it.
Create a wrapper function that calls the original function, then one you pass in.
If the original function is an Ajax call and you're trying to replace one of its handlers, that's a different issue, though you might be able to use jQuery's $.when(original).then(function () { ... }) depending on your actual needs.

Help with jQuery functions executing prematurely

I have a click function:
jQuery("#element").click(function(e){
var op = jQuery("#box").GetOp();
op.flag1 = false;
op.flag2 = true;
executeFunction();
jQuery("#box").reload();
});
I want the functions executeFunction(); and jQuery("#box").reload(); to execute in serial order only after the previous two lines are executed.
EDIT: The functions should execute synchronously.
Other threads have suggested using callbacks, but I'm not sure how I can use it in my case.
Any suggestions?
Javascript is inherently synchronous so, if your code does not execute in serial order, maybe executeFunction() is calling some async behaviour, like AJAX requests or setTimeout/setInterval things.
A posible solution in that case is to pass a function to executeFunction() and call it when the async behaviour is done:
jQuery('#element').click(function(e){
var op = jQuery('#box').GetOp();
op.flag1 = false;
op.flag2 = true;
executeFunction(function(){
jQuery('#box').reload();
});
});
And changing executeFunction(fn) to call the function on async behaviour success.
Normally, JavaScript is single thread programming. But you can simulate thread by using setTimeOut to automatically call the defined function. For your source code, it should work synchronously if you don't work any setTimeOut statement in any method.

AJAX workflow: How do I order the execution of these functions?

I'm trying to figure the best way to get my functions executing in the correct order.
I have 3 functions
function 1 - squirts OPTIONs into a SELECT via JSON and marks them as selected
function 2 - squirts OPTIONS into a 2nd SELECT and marks them as selected
function 3 - gets the values from the above SELECTs along with some additional INPUT values, does an AJAX GET resulting in JSON data, which is read and populates a table.
With JQuery Onload, I execute:
function1();
function2();
function3();
I'm finding function3 is executing before the SELECTs have been populated with OPTIONS and hence the table has no results, because the values sent in the GET were blank.
I know this is probably a very simple problem and that there are probably a dozen ways to accomplish this, but basically I need the best way to code this so that function3 only runs if function1 and 2 are complete.
I've come into Javascript via the back door having learnt the basics of JQuery first!
Thanks for your assistance.
Javascript executes synchronously, which means that function3 must wait for function2 to complete, which must wait for function1 to complete before executing.
The exception is when you run code that is asynchronous, like a setTimeout, setInterval or an asynchronous AJAX request.
Any subsequent code that relies on the completion of such asynchronous code needs to be called in such a manner that it doesn't execute until the asynchronous code has completed.
In the case of the setTimeout, you could just place the next function call at the end of the function you're passing to the setTimeout.
In the case of an AJAX call, you can place the next function call in a callback that fires upon a completed request.
If you don't want the execution of the subsequent function to occur every time, you can modify your functions to accept a function argument that gets called at the end of the asynchronous code.
Something like:
function function1( fn ) {
setTimeout(function() {
// your code
// Call the function parameter if it exists
if( fn ) {
fn();
}
}, 200);
}
function function2() {
// some code that must wait for function1
}
onload:
// Call function1 and pass function2 as an argument
function1( function2 );
// ...or call function1 without the argument
function1();
// ...or call function2 independently of function1
function2();
I recommend you use a Promises library. You can hack simple solutions like other answers suggest, but as your application grows, you'll find you are doing more and more of these hacks. Promises are intended to solve these kinds of problems when dealing with asynchronous calls.
The CommonJS project has several Promises proposals which you should check out. Here is a question I asked on SO about Promises a while back with links to other solutions. Learn more about Promises in this Douglas Crockford video. The whole video is good, but skip to just past half way for promises.
I'm using the FuturesJS library currently as it suits my needs. But there are advantages to other implementations as well. It allows you to do sequences very easily:
// Initialize Application
Futures.sequence(function (next) {
// First load the UI description document
loadUI(next); // next() is called inside loadUI
})
.then(function(next) {
// Then load all templates specified in the description
loadTemplates(next); // next() is called inside loadTemplates
})
.then(function(next) {
// Then initialize all templates specified in the description
initTemplates();
});
Even more powerful is when you need to join async events together and do another action when all of the other async events have completed. Here's an example (untested) that will load a bunch of HTML files and then perform an action only once ALL of them have completed loading:
var path = "/templates/",
templates = ["one.html","two.html","three.html"],
promises = [];
$.each(templates, function(i,name) {
promises[i] = Futures.promise();
var $container = $("<div>");
$container.load(path+name, function(response,status,xhr) {
promises[i].fullfill();
}
});
Futures.join(promises, {timeout: 10000}) // Fail if promises not completed in 10 seconds
.when(function(p_arr) {
console.log("All templates loaded");
})
.fail(function(p_arr) {
console.log("Error loading templates");
});
This might be overkill for your application. But if the application is growing in complexity, using promises will help you in the long run.
I hope this helps!
invoke function2 inside of function1 and function3 inside of function2.
It's not clear why f1 and f2 are executing before f3.
Also, are you using the preferred $(document).ready() or some variation of onload?
It might be helpful if you provide a reproducible test case.
fun3() will only run after both are ready. It might run twice. You can fix this with a lock inside fun3() you would need a Singleton to guarantee it works correctly.
var select1ready = false, select2ready = false;
fun1()
{
// do stuff
select1ready = true;
fun3();
}
fun2()
{
// do stuff
select2ready = true;
fun3();
}
fun3()
{
if (select1ready && select2ready)
{
}
}
fun1();
fun2();

Categories

Resources