why is my exception not being caught? - javascript

I am writing a jQuery plugin that lets users add references to their article. Basically, when the enter key is pressed while the user is focused on the reference input, the script checks the URL through my AJAX script to make sure that it's a working URL. If it's valid, a button is added to a list of references that the user can see. It will also update a hidden input that contains a comma-separated list of URL's.
I am very new to the concept of JS exceptions... I am currently getting an error saying Uncaught [object Object]. The error happens where I throw the variable 'info'. Any ideas?
(function($){
$.fn.extend({
references : function(options) {
var defaults = {
sample_div : '#sample-ref',
remove_button : '#removereference',
update_div : '#references',
hidden_input : 'input[name="references"]',
saved_input : 'input[name="saved-refs"]',
ajax_url : 'ajax.php',
search_input : '#reference'
};
var options = $.extend(defaults, options);
var count = 0;
function addReferenceBlock(ref_title){
var replacements = {
ref_title : ref_title,
ref_url : ref_url
};
var block = $(options.sample_div).html();
$.each(replacements, function(index, value){
block.replace(new RegExp('{'+index+'}', 'g'), value);
});
$(options.update_div).append(block);
}
function checkReference(url){
var postData = 'reference='+url;
$.ajax(
{
dataType: "xml",
type: "POST",
data : postData,
cache: false,
url: options.ajax_url
})
.done(function(xml, textStatus, jqXHR){
if(textStatus === 'success'){
$(xml).find('success').each(function(){
console.log('checking '+url+'...');
var info = $(this).find('pagetitle');
throw info;
});
$(xml).find('error').each(function(){
throw false;
console.log($(this).find('message').text());
});
} else {
console.log(jqXHR);
}
});
}
function init(element, options){
$(options.search_input).enterKey(function(e){
try {
checkReference($(options.search_input).val());
} catch($status){
if($status !== false){
addReferenceBlock($status);
updateReferenceInput($(options.search_input).val());
} else {
alert($status);
}
}
e.preventDefault();
});
}
return $(this).each(function(){ init(this, options); });
}
});
})(jQuery);

Your try block calls the checkReference function. Your checkReference function calls done. done does not call the anonymous function which throws your error; it sets up an event handler so it can be called by the system later. Thus, your stack trace is not what you think it is.
EDIT
Why does "done" not call the code inside of it?
Because if it did, it would not be asynchronous. Let's mock this with setTimeout rather than AJAX, same principles apply:
function foo(how) {
throw("In foo " + how + " (look at the stack trace by clicking on the triangle)");
}
function callFooAsynchronously() {
console.log("calling foo asynchronously");
setTimeout(function() {
foo("asynchronously");
}, 1000);
console.log("finished calling foo asynchronously");
}
function callFooSynchronously() {
console.log("calling foo synchronously");
foo("synchronously");
console.log("finished calling foo synchronously");
}
function main() {
callFooAsynchronously();
callFooSynchronously();
}
main();
The output is as follows:
calling foo asynchronously js:18
finished calling foo asynchronously js:22
calling foo synchronously js:26
Uncaught In foo synchronously (look at the stack trace by clicking on the triangle) js:14
foo js:14
callFooSynchronously js:27
main js:34
(anonymous function) js:37
Uncaught In foo asynchronously (look at the stack trace by clicking on the triangle) js:14
foo js:14
(anonymous function)
The synchronous call will start, then throw an exception. Due to the exception, "finished calling foo synchronously" is never displayed. The stack trace shows call from the snippet execution environment, calling to main, which calls callFooSynchronously, which, ultimately, calls foo.
The asynchronous call will display the starting message, attach a timeout handler, then display the finished message, then exit. This concludes callFooAsynchronously. One second later, the browser will remember there is something it needs to do, and this is reflected in the stack trace: the anonymous function passed to setTimeout is run, which in turn runs foo. Note how main and callFooAsynchronously are not a part of the stack trace: they have set the alarm, then left the building. callFooAsynchronously, despite its name, never calls foo, and neither does setTimeout.
The browser calls the anonymous function in setTimeout directly, just as it calls directly the onreadystatechange function on an XMLHttpRequest (the function that ultimately calls the function you passed to done), which is attached, but not called, by jQuery.ajax.
If done called your function, it would be executed immediately after you made the ajax call, and not when the response arrives, because that is when done gets executed.

In JS, you can throw errors using error-strings like: throw new Error('You did something wrong')
So in your case, maybe you can try: throw new Error(info.text()) which will fetch the text inside the .pagetitle element.
Is this what you want?

Related

callback returns Uncaught TypeError: callback is not a function

Background info
I am making an application which fetches data from the data via an AJAX call. If the success method meets the requirements, it calls a function and passes the callback parameter along as an argument. The callback gets invoked in a for loop then.
Problem
Whenever I invoke the callback function, it throws the error Uncaught TypeError: callback is not a function (on line 39)
Sources I have looked up and tried
Let me start off by saying that I have already done a console.log() on the callback parameter and the value is correct.
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
Uncaught TypeError: callback is not a function
add callback to function(e) Uncaught TypeError: callback is not a function
Uncaught TypeError: callback is not a function
My code
function Query(eventObject, button, callback)
{
//replaced not relevant code here with a comment.
success: function(response)
{
if (button === "getB")
{
//success fetches correctly. Already checked whether response could be empty. This is not the case
response = JSON.parse(response);
if (callback)
{
//pass the callback along
rollOut(response, callback);
}
}
}
}
//THE FUNCTION I AM TRYING TO INVOKE
function setCheckboxes(valueToCompare)
{
console.log(valueToCompare);
}
function rollOut(jsonResponse, callback)
{
$(`.show-divSet`).on(`click`, function () {
for (let i = 0; i < jsonResponse.length; i++)
{
if (jsonResponse[i]["version"] !== "")
{
//CONSOLE SHOWS ME THE CORRECT VALUE
console.log(callback);
//THIS IS LINE 39. THIS IS WHERE THE ERROR IS THROWN
callback(jsonResponse[i]["version"]);
}
}
});
}
How I instantiate my code all
$(function () {
// I have already tried setCheckboxes WITHOUT quotes, but unfortunately this didn't work either
Query("", "getB", "setCheckboxes");
});

Interpreting output after using callback in javascript

I am new to javascript and I am trying to understand callbacks. I am not able to understand why 20 is getting printed before 10. My understanding is for a callback function like - func1(parameter,func2()) , func2() is the callback function, which gets executed after func1 executes with the "parameter" passed to func1. Is my understanding correct?
function timePass(length){
console.log("finished after doing timePass for "+length +" seconds")
}
timePass(10,timePass(20));
OUTPUT BELOW:
finished after doing timePass for 20 seconds
finished after doing timePass for 10 seconds
You are not really creating a callback function but actually calling timePass(20) before everything else on your last line of code.
To pass a callback function you should do something like this:
function timePass(length,callback){
console.log("finished after doing timePass for "+length +" seconds")
if(typeof(callback) == "function")
callback(20);
}
timePass(10,timePass);
This is because you execute the function timePass and then - adding the result as argument number 2.
Explaining what is happening:
First you define new function "timePass", The function printing on the console.
Second you execute timePass(10, /*But here you execute it again*/ timePass(20)).
The function timePass(20) will be executed first because you added ().
() == execute. If you just pass the name of the function, it will be passed as function. When you use () it will be executed and then the result will be passed as argument.
EXAMPLE OF USING CALLBACK
function timePass(length, callbackFunction){
console.log("finished after doing timePass for "+length +" seconds");
// check if the function caller is included callback parameter
// and check if it is function - to prevent errors.
if (callbackFunction && typeof callbackFunction == "function") {
// Execute the callback (timePass)
callbackFunction(20);
}
}
// Here you say, Execute timePass with arg 10, and then call timePass
timePass(10, timePass);
// and now callbackFunction defined above will be == timePass
// You can do also
timePass(10, anotherFunction)
// So another function will be executed after console.log()
USE CASES
Most often callbacks are used while we working with async code.
For example: Jsfiddle
// Imagine we have function which will request the server for some data.
function getData(index) {
// The request - response will took some time
// 0.1s ? 15s ? We don't know how big is the data we downloading.
var data;
// Imagine this is an AJAX call, not timeout.
setTimeout(function() {
// after 30ms we recieved 'server data'
data = 'server data';
},30)
return data;
}
var users = getData('users');
console.log(users); // undefined - because we returned "data" before the AJAX is completed.
/*
So we can change the function and adding an callback.
*/
function getAsyncData(index, callback) {
var data;
// Imagine this is an AJAX call, not timeout.
setTimeout(function() {
// after 30ms we recieved 'server data'
data = 'server data';
callback(data);
},30)
}
getAsyncData('users', function(data) {
console.log(data); // 'server data'
});
// OR
function processData(data) {
console.log(data);
}
getAsyncData('users', processData); // processData also logs 'server data'
basically when the interpreter is looking at this, it will call timepass(20) to evaluate the result (which is nothing as you have no return returning something), which then it tries to pass into the outer function.
i.e.
doFunction( doSomethingElse() );
if doSomethingElse returns 1, it must evaluate that before it can pass that 1 into doFunction.
Fundamentally, you have not actually passed a callback, you have called the function. Perhaps you meant:
callback = function() { somecode; }
target = function(data, callback) { console.log('hi'); callback(); }
target(10, callback);
notice the lack of () i.e. callback not callback()

recursive calls to ajax cause memory leak?

Does the following code logic cause the original call's stack frame to contain the memory from each subsequent call (causing excessive memory usage)?
function foo (arg) {
bar(arg);
}
function bar (arg) {
$.ajax({
success: function (data) {
if (data['result'] == 'continue') {
bar(data['nextarg']);
} else if (data['result'] == 'done') {
alert('done!');
}
}
});
}
Your code is not recursive. $.ajax is asynchronous, so the stack pointer isn't waiting for bar to return.
Instead, $.ajax fires an asynchronous process, then continues until it hits either an explicit or implicit return. In your case, there is an implicit return at the end of bar.
Your function consumes no more memory than it should.
function bar (arg) {
// calls $.ajax, which is async, so it fires "whenever"
$.ajax({
// when the ajax is complete/successful, this function is called
success: function (data) {
if (data['result'] == 'continue') {
bar(data['nextarg']);
} else if (data['result'] == 'done') {
alert('done!');
}
}
})
// exits immediately after
}
I was curious to see if this was the case, so I tested it using a simplified version. The code below is an ajax call that binds calls to itself in its own success routine, printing the call stack each time. As it turns out, the call stack is the same each time, i.e. no memory leak.
I have a hunch that the fact that the call is asynchronous may come into play - i.e. there isn't actually any recursion since the success handler is called by the browser directly on the success of the AJAX call, not from within the last invocation of the function.
Here is the code I used to test the hypothesis:
var count = 0;
function bar() {
$.ajax("/", {
success: function () {
count++;
console.trace();
if (count < 4) bar();
}
});
}
bar();
And here is a live JSFiddle that shows you that the call stack is exactly the same on each invocation: https://jsfiddle.net/dtrgak9o/

New to Javascript - Callback issue

I am new to Javascript programming coming from a Java and Objective C background. I am looking to learn a bit more about Javascript for hybrid mobile applications.
In doing so I am trying to do a login with a call back but I am having a little trouble understanding both the syntax and the way a callback works.
First up I am calling the following login function which just creates an ajax call to fetch some JSON at the minute for testing purposes:
testLogin.loginWithUsername ("test", loginCallback);
This works OK as I can see the 200 OK Status and the expected JSON in logging.
However the call back "loginCallBack" never gets called.
It is as follows:
loginCallback: {
success: function(id) {
alert ('success');
}
failure: function (id, error) {
alert ('failure');
}
}
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line. I can change it and the failure function to = function(id) and it the code runs then but the callback is never called.
I am using a library for the login that states the call back required is an object that needs a success and failure function and the code above is the given example.
So first off I don't understand why the above syntax works in the sample code but gives me an error when I run it?
Secondly am I calling the callback correctly? Both the loginWithUsername call and the loginCallback function are in the same Login.js file.
Here is an example how callback works:
First thing: you need to create a new object containing your functions/methods. Properties and methods are listed comma seperated.
// Creating new object with callback functions
var loginCallback = {
success: function(id) {
alert ('success');
} , // Add a comma
failure: function (id, error) {
alert ('failure');
}
}
function loginWithUsername(username, callback) {
if (username === 'test') {
var successId = 1;
callback.success(successId);
} else {
var errorId, errorMsg;
errorId = 0;
errorMsg = 'Error';
callback.failure(errorId, errorMsg);
}
}
Now you can call the function:
loginWithUsername('test', loginCallback);
And the result should be 'success'.
Edit:
But you can do this without an object, by passing the function directly:
// Creating function
function showMessage(message) {
alert(message);
}
function loginWithUsername(username, callback) {
if (username === 'test') {
callback('success');
} else {
callback('failure');
}
}
// Pass function
loginWithUsername('test', showMessage); // Result: 'success'
loginWithUsername('abcd', showMessage); // Result: 'failure'
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line.
Each property: value pair in an object literal must be separated with a comma.
}, /* Your comma is missing which is why you get a syntax error */
failure:
This:
loginCallback: {
is only acceptable if you want to define a property inside an object literal.
This:
testLogin.loginWithUsername ("test", loginCallback);
is using a variable.
You probably want:
var loginCallback = {
but it is hard to tell without more context.

Boolean is true in Flash, but false in Javascript

I have this function in Flash:
public function checkFile(file:String):Boolean{
var b:Boolean;
var responder:Responder = new Responder(function(reply:Boolean):void{
b=reply;
msg("vid_"+file+".flv "+ "exists? " + reply);
setState("ready");
status = "ready";
},
function(res:Object):void{
trace("checkFile call failed");
});
mync.call("checkFile",responder,"vid_"+file);
return b;
}
I can confirm that the reply variable is true, but return b ends up false:
This is the javascript I use to call the flash function:
function checkFile(){
alert(thisMovie("vidRecorder").checkFile(currentVid));
}
And that opens up a message box saying false, while the flash file displays true
What's going on? How can I fix it so that my function returns the same value as reply?
This happens because the anonymous function in your responder is executed asynchronously.
When your checkFile() function returns the value of b is still false. Eventually, your anonymous function is executed and b gets set to true ... but it's too late in this case, as your checkFile() function has already returned false.
To work around this, you might consider doing this in a slightly different fashion:
When your anonymous function is executed, have it call out to javascript with the asynchronous response. Something like this:
public function checkFile(file:String):void {
var responder:Responder = new Responder(function(reply:Boolean):void{
msg("vid_"+file+".flv "+ "exists? " + reply);
setState("ready");
status = "ready";
ExternalInterface.call('someJavascriptFunction', reply);
},
function(res:Object):void{
trace("checkFile call failed");
});
mync.call("checkFile",responder,"vid_"+file);
// note we no longer return a value here
}
In the above code, we call a new Javascript function and provide it the result of the asynchronous operation.

Categories

Resources