Handling errors with jQuery $.getScript - javascript

I am using a function that automatically loads .js files for modules with jQuery .getScript() function. The problem is that if the loaded script has any errors in it I cannot find a way to display the error line from the file loaded. I found a way to display the error type and error message but not the error line.
jQuery.getScript(main.constants.BASEURL + main.modules[activeModule].path + 'js/functions.js')
.done(function() {
Module.init();
})
.fail(function(jqxhr, settings, exception) {
errorObj = {};
if (arguments[0].readyState == 0) {
errorObj.message = 'Failed to load script!';
//script failed to load
}
else {
errorObj.type = arguments[1];
errorObj.message = arguments[2]['message'];
errorObj.lineNo = ??; //This is what I need to find
//script loaded but failed to parse
}
console.log(errorObj);
});

If you dynamiclly add a new script tag to head you will see line numbers, use scripts element onload to init the module

Related

catching an error or exception thrown from a dynamically appended script element - possible?

I want to stop script execution in a dynamically appended script (as in include_guard) by throwing an error from the appended file. Then I want to catch this error from the file that did the "appending" (as in "making things clean").
index.html
<!DOCTYPE html>
<html>
<head>
<title>pickle</title>
</head>
<body>
<script type="text/javascript">
var de = document.createElement("script");
de.src = "file.js";
document.head.appendChild(de);
</script>
</body>
</html>
file.js
throw new Error("blabla");
How can I catch the error thrown ?
Something like this doesn't catch anything (probably because the appending is happening in a different thread):
var de = document.createElement("script");
de.src = "file.js";
try {
document.head.appendChild(de);
}
catch(e) {
console.log("got it");
}
I also tried setting an error listener to the window object, which does receive error notification, but the error is not caught.
Reason I want to do that: I wrote a javascript includer that works pretty much like the c/c++ #include directive with support for a #pragma once-like feature.
If a file is included 2+ times and it was tagged as once, I need to stop execution for this file - by throwing or erroring the script from inside the once() function.
Note: it aleady works. My once() function throws a custom include_guard object and script execution is halted. If possible, I want to catch that error and print a warning instead, to make things look cleaner (not a life or death situation...).
It is possible to cancel an error by listening to it in window.onerror and returning true from the handler.
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event
Example:
window.onerror = function(event, source, lineno, colno, error) {
if (error instanceof my_custom_error) {
console.warn(my_custom_error + " was canceled.");
return true;
}
//don't disrupt anything else
return false;
}
In the specific issue of the OP tho, error is null and the error string in event is a generic "Script error" message (tested on Chrome), so this method can't be used.
It seems the reason for error to be null is that the error is thrown from a different file.

lightbox2 fallback when cdn js cloudflare is unavailable

I'm loading lightbox2 via the following CDN //cdnjs.cloudflare.com/ajax/libs/lightbox2/2.7.1/js/lightbox.min.js
if this is unavailable then I want to fallback to my core files. How do I check to see if lightbox has already been defined so as to avoid loading my core files.
I tried typeof lightbox === "undefined" but that always returns true forcing my core files to be loaded.
I have fallbacks for jquery, angular etc already - it is lightbox2 that I am having issues with checking if it has already been loaded.
Yes, the problem here is that there is nothing in global scope because lightbox doesn't add anything to it. (see this SO question). That's why you can't test it like window.lightbox.
A workaround is to load the script with an ajax request like in the demo below. The getScript method is a shorthand Ajax function (see here for details).
There you have a fail callback where you can add your local script to the DOM if loading of the cdn fails.
You can do the same for any file that you're loading from a cdn (e.g. the stylesheet of lightbox).
var addLocalScript = function (src) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = src; // use this for linked script
//script.text = "alert('voila!');" // use this for inline script
document.body.appendChild(script);
};
$(function () {
var url = 'https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.7.1/js/lightbox.min.js';
$.getScript(url)
.done(function (script, textStatus) {
console.log(textStatus);
})
.fail(function (jqxhr, settings, exception) {
console.log('cdn load failed');
//add local script
addLocalScript('js/lightbox/lightbox.min.js');
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.7.1/css/lightbox.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="http://lorempixel.com/400/200"/>

Fire Elfinder Error Dialog from Command

I am working on making my own command (view commands) for elFinder, and it works pretty good.
The only thing that I have a problem with is when I do my custom ajax call to the connector, the error doesn't popup. It is valid JSON error output.
I was thinking if it somehow was possible to fire the error dialog myself from the command file?
I'm trying to do this from inside the this.exec = function(data) { ... } function in my command.
Your error call should be like this within that function. this.fm.error() or fm.error() in this case is used to fire the error dialog.
this.exec = function(data) {
var fm = this.fm,
dfrd = $.Deferred()
.fail(function(error) {
fm.error(error);
})
return dfrd;
}

Debugging a Windows store app - error messages always show the same line number

I've set up error logging on my windows store app, which reports the error message and the line number in the code.
I've been getting two error messages from the same line, line 301. The error messages are
The process cannot access the file because it is being used by another process.
Access is denied.
Based on the First error message I presume the error is with my autosave function, but without the line number I can't say where it's failing. Here's my autosave code
function autosave()
{
if ((localSettings.values["useAutoSave"] == null || localSettings.values["useAutoSave"] == "true")) {
editorContent = editor.textContent;
var text_length = editorContent.length;
if (editedSinceSave && text_length > 0) {
localSettings.values["lastContent"] = text_length;
setStatus("<span class='loader'></span>autosaving", 2000);
writeTempFile();
}
}
window.setTimeout(autosave, _autosave_timeout);
}
function writeTempFile()
{
try{
tempFolder.createFileAsync("tempFile.txt", Windows.Storage.CreationCollisionOption.replaceExisting)
.then(function (theFile) {
return Windows.Storage.FileIO.writeTextAsync(theFile, editor.textContent);
}).done(function () {
localSettings.values["lastPos"] = _lastStartPos;
});
}
catch (e) {
// statements to handle any exceptions
logError(e); // pass exception object to error handler
}
}
Even we I move all my functions around and recompile my code, the error is always at line 301. I suspect that the errorline I'm seeing is actually from whatever underlying js files are used to run my app, but I don't know where to access them. How the hell do I debug this?
Make sure there's not a capability that you have not declared. It doesn't look like your code is using anything special, but it's worth a try.

Handling errors in jQuery.getScript

jQuery's getScript function doesn't seem to support an error callback function. I can't use the global ajax error handling code here, a local error function would be ideal.
Documentation that the callback gets data/textStatus seems incorrect - the callback gets neither.
Any suggestions on how I detect that a call to getScript failed (server not available, for instance)?
EDIT: Just looked at source, and it seems like the callback is only invoked on success, with data always set to null and textStatus not defined (since it's a success-only callback, I presume). The documentation is very incorrect for this function.
As of jQuery 1.5 you can append a .fail to your call to getScript.
$.getScript('foo.js', function(){
//script loaded and parsed
}).fail(function(){
if(arguments[0].readyState==0){
//script failed to load
}else{
//script loaded but failed to parse
alert(arguments[2].toString());
}
})
http://api.jquery.com/jQuery.getScript/#handling-errors
For cross domain script tags, the success event fires but the error event does not; no matter what syntax you use. You can try this approach:
Create an error handler and set it to fire after few seconds using handle = window.setTimeout
Inside your success callback function, cancel the timeout using window.clearTimeout(handle)
Sample code:
var timeoutId; // timeout id is a global variable
timeoutId = window.setTimeout(function() {
alert("Error");
}, 5000);
$.getScript("http://other-domain.com/script.js", function(){
window.clearTimeout(timeoutId);
});
The global JQuery Ajax-ErrorHandler will work!
Prior to the $.getScript-Call setup the Error Handler to cach the error.
$(document).ajaxError(function(e, xhr, settings, exception) {
alert('error in: ' + settings.url + ' \n'+'error:\n' + exception );
});
As described in the JQuery manual: http://api.jquery.com/ajaxError/.
jquery.ajax has a alternative way to handle error
jQuery.ajax({
type: "GET",
url: 'http://www.example.com/script_test.js',
dataType: "script",
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log('error ', errorThrown);
},
success:function(){
console.log('success');
}
});
Unless you don't use jQuery 2.0+ $.getScript seem to be the wrong choice, because it does not provide any error handling capabilities while making cross-domain requests. None of those: fail, complete, error, statusCode will work. I've checked it with jQuery 1.11.2
Solution with setTimeout will be too slow if you have to load fallback script when the first will fail.
In this case script.onerror callback seem to be the cleanest way.
var script = document.createElement('script');
document.head.appendChild(script);
script.onload = function () {
// loaded
};
script.onerror = function () {
// failed
};
script.src = 'https://example.com/main.js';
In combination with $.Deferrred provides reliable way to build complex loaders.
var libLoaded = $.Deferred();
var script = document.createElement('script');
document.head.appendChild(script);
script.onload = libLoaded.resolve;
script.onerror = function () {
// load fallback script, no error handling
$.getScript('/fallbackLib.js')
.done(libLoaded.resolve)
};
script.src = 'https://example.com/lib.js';
$.when(libLoaded).then(
// fanally I can use my lib safly
);
This is a bit of a hack, but..
You could declare a variable inside the scripts you load and check for it after you've loaded a script (assuming that the complete-function still fires):
script_test.js:
var script_test = true;
And then:
$.getScript("script_test.js", function ()
{
if (typeof script_test !== undefined) alert("script has been loaded!");
});
Or you could just try and see if whatever is in your script, actually exists--functions, variables, objects, etc.
A more generic way to do this would be adding a self-executing function inside the scripts you want to load, and make them execute a function in your "main" script:
main_script.js:
function scriptLoaded(scriptName)
{
alert(scriptName + " loaded!");
}
$.getScript("script_test.js");
script_test.js:
(function ()
{
scriptLoaded("script_test.js");
})();

Categories

Resources