Pass Exception from plugin to Javascript - javascript

For some reasons I have a javascript that create an entity record and a plugin will fire on post create. If the pugin throw an exception, it does NOT display to the user as the javascript is involved. I am wondering if there is a way to pass the exception from the plugin to javascrit so it can display it to the user.
Thanks.

Do you receive any http status code error like 40*, 500, 50* , if you use Odata, you have a callback to get the error. Javascript exception may not be throw.
Example:
.ajax({
type: “POST”,
contentType: “application/json; charset=utf-8″,
datatype: “json”,
url: serverUrl + ODATA_ENDPOINT + “/” + odataSetName,
data: jsonEntity,
beforeSend: function (XMLHttpRequest) {
//Specifying this header ensures that the results will be returned as JSON.
XMLHttpRequest.setRequestHeader(“Accept”, “application/json”);
},
success: function (data, textStatus, XmlHttpRequest) {
},
error: function (XmlHttpRequest, textStatus, errorThrown) {
if (errorCallback)
errorCallback(XmlHttpRequest, textStatus, errorThrown);
else
alert(“Error on the creation of record; Error – “+errorThrown);
}
});
}

Checking the XMLHttpRequest readyState and status should do the trick:
function createRecord(eObject, eName) {
var jsonEntity = window.JSON.stringify(eObject);
var u = Xrm.Page.context.getServerUrl();
var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
var rec = new XMLHttpRequest();
var p = u + ODATA_ENDPOINT;
rec.open('POST', p + "/" + eName, false);
rec.setRequestHeader("Accept", "application/json");
rec.setRequestHeader("Content-Type", "application/json; charset=utf-8");
rec.send(jsonEntity);
if (rec.readyState == 4) {
if (rec.status == 200) {
var r = JSON.parse(rec.responseText).d;
return r;
}
else {
var error;
try {
// To get the exception from the responseXML
// I get an error when trying to use JSON.parse(rec.response)
// Unexpected token <
// I would much rather use JSON.parse
// than fiddling with the XML
// Please let me know if you find how to
// get the error message with JSON.parse
var xmlDoc = rec.responseXML;
var error = xmlDoc.childNodes[0]
.childNodes[0]
.childNodes[0]
.childNodes[1]
.childNodes[0].nodeValue + "."; // The error message
}
catch (e) {
// unable to get error message from response
error = "General Error";
}
return error;
}
}
// there is a problem
// maybe return general error message
return "General Error";
}

Thanks for all of you. I did resolve the issue by modifying part of my code to the following:
rec.send(jsonEntity);
if (rec.readyState == 4) {
if (rec.status >= 200) {
var newRecord = JSON.parse(rec.responseText).d;
return newRecord;
}
else {
var error;
var er;
try {
error = rec.responseText.toString();
error = error.substring(error.lastIndexOf("value\": ")+9,error.lastIndexOf("\""));
alert(error);
}
catch(e) {
error = rec.responseText.toString();
error = encodeURIComponent(error);
er = error.substring(error.lastIndexOf("value%22%3A%20%22")+17,
error.lastIndexOf("%22%0D%0A%7D%0D%0A%7D%0D%0A%7D"));
er = decodeURIComponent(er);
return er;
}
}

Related

Why is my $.ajax not showing up in Network tab, but opening in a new tab works?

Here is my AJAX code:
jQuery.ajax({url: url,
method: 'GET',
data: getParams,
/*success: function (json, textStatus, jqXHR) {
if(jQuery.active <= 1){
waitDialog.removeWaitDialog();
}
createProcessButtonEvent();
ajaxError = false;
returnFunction(jqXHR.responseJSON);
},*/
complete: function(jqXHR, textStatus, errorThrown) {
if(jQuery.active <= 1){
waitDialog.removeWaitDialog();
}
createProcessButtonEvent();
var response;
if (typeof jqXHR.responseJSON === 'object') {
response = jqXHR.responseJSON;
} else {
response = jqXHR.responseText;
}
if(response.errors.length == 1){ // jsonResults.message != ''
if(!warningMessage){ //hard coded for ad designer
jQuery('#alertMessageText').text(response.errors[0].message);
jQuery('#alertMessage').show();
jQuery('#waitDialog').jqmHide();
ajaxError = true;
return;
}
warningMessage.displayMessage(response.errors[0].message);
jQuery('.popup').modal('hide');
jQuery('.popup').not('.persist').remove();
}
if (response.errors.length > 1){
for(var n = 0; n < response.errors.length; n++){
if (response.errors[n].id == 1){ // 2005
window.location.href = '/login?destination=' + encodeURIComponent(window.location.pathname + window.location.search);
}
if (response.errors[n].id == 9500){
statusMessage.displayMessage(response.errors[n].message);
}
}
ajaxError = true;
//if(errorFunction){
// errorFunction(jsonResults);
//}
waitDialog.removeWaitDialog();
}
if (!ajaxError) {
returnFunction(jqXHR.responseJSON);
}
},
dataType: 'json',
contentType: 'application/json'
});
I tell it to go to http://127.0.0.1/api/parameter, where the parameter is an invalid resource. My API returns in a new tab:
{"errors":[{"id":3,"message":"GET route not defined for /api/parameter"}],data:{}}
I have it returning with a 500 status code because accessing an invalid resource is an error. When I call the actual AJAX, I get jqXHR.responseJSON is null, and jqXHR.responseText is ''.
I have tried using both success: and error: blocks, and tried the complete: because it seemed like my API was resolving the call after the error block had been called, as you can see with the comments.
So I get TypeError: response is null, because my response object is never populated, and the strangest thing is that my call to parameter?parameters=here is never available to inspect in the Network
Since I have control over the API, I changed this specific error to return with status code 501 Not Implemented, instead of 500, and it seems to work. It looks like this was a very unique edge case.

jquery ajax call is not working in IE9

I am having some trouble with the code below. It will not run in IE9. It works fine in other browsers though.
I have placed an alert inside the code but that piece of code is not reached.
anyone has got any idea how to solve this issue?
NWF$.ajax({
url: 'http://pdfservice/training/',
data: JSON.stringify(dataJSON),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: 'POST',
cache: false,
success: function (fileName) {
alert('ok!');
window.location.href = 'http://pdfservice/training/?meeting=' + fileName;
},
error: function (result) {
alert(JSON.stringify(result));
}
});
I just changed the fail to error and this is the error that I get:
{"readyState":0,"status":0,"statusText":"No Transport"}
Jquery w Ajax for IE9 is broken.
This is supported through a jquery plugin
"Implements automatic Cross Origin Resource Sharing support using the XDomainRequest object for IE8 and IE9 when using the $.ajax function in jQuery 1.5+."
This happens because your JSON data is corrupt.
Fix your JSON data, you can use JSONLint to validate your JSON response to make sure it's valid JSON.
Old post, figured I'd add my findings from AJAX POST request on IE fails with error "No Transport"?
I'm adding the code in the event it gets deleted:
if (!jQuery.support.cors && window.XDomainRequest) {
var httpRegEx = /^https?:\/\//i;
var getOrPostRegEx = /^get|post$/i;
var sameSchemeRegEx = new RegExp('^'+location.protocol, 'i');
var xmlRegEx = /\/xml/i;
// ajaxTransport exists in jQuery 1.5+
jQuery.ajaxTransport('text html xml json', function(options, userOptions, jqXHR){
// XDomainRequests must be: asynchronous, GET or POST methods, HTTP or HTTPS protocol, and same scheme as calling page
if (options.crossDomain && options.async && getOrPostRegEx.test(options.type) && httpRegEx.test(userOptions.url) && sameSchemeRegEx.test(userOptions.url)) {
var xdr = null;
var userType = (userOptions.dataType||'').toLowerCase();
return {
send: function(headers, complete){
xdr = new XDomainRequest();
if (/^\d+$/.test(userOptions.timeout)) {
xdr.timeout = userOptions.timeout;
}
xdr.ontimeout = function(){
complete(500, 'timeout');
};
xdr.onload = function(){
var allResponseHeaders = 'Content-Length: ' + xdr.responseText.length + '\r\nContent-Type: ' + xdr.contentType;
var status = {
code: 200,
message: 'success'
};
var responses = {
text: xdr.responseText
};
try {
if (userType === 'json') {
try {
responses.json = JSON.parse(xdr.responseText);
} catch(e) {
status.code = 500;
status.message = 'parseerror';
//throw 'Invalid JSON: ' + xdr.responseText;
}
} else if ((userType === 'xml') || ((userType !== 'text') && xmlRegEx.test(xdr.contentType))) {
var doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = false;
try {
doc.loadXML(xdr.responseText);
} catch(e) {
doc = undefined;
}
if (!doc || !doc.documentElement || doc.getElementsByTagName('parsererror').length) {
status.code = 500;
status.message = 'parseerror';
throw 'Invalid XML: ' + xdr.responseText;
}
responses.xml = doc;
}
} catch(parseMessage) {
throw parseMessage;
} finally {
complete(status.code, status.message, responses, allResponseHeaders);
}
};
xdr.onerror = function(){
complete(500, 'error', {
text: xdr.responseText
});
};
xdr.open(options.type, options.url);
//xdr.send(userOptions.data);
xdr.send();
},
abort: function(){
if (xdr) {
xdr.abort();
}
}
};
}
});
};
jQuery.support.cors = true;

order of operations parse cloud

I was wondering what the order of operations are in the parse cloud. I currently am running into trouble trying to do multiple things at once inside my job on the cloud. I am currently trying to make an HTTP request for each user in my user table (there are 2) and then get the webpage or httprequest.text from the webpage. My code is as followed
Parse.Cloud.job("WeatherUpdates2", function(request, status) {
var query = new Parse.Query(Parse.User);
query.exists("City");
query.each(
function(result){
var object = result;
console.log(object.id);
var city = object.get("City");
city = city.replace(" ", "");
city = city.replace(" ", "");
// get the country code.
var countryCode = object.get("CountryCode");
var woeidUrl = "http://where.yahooapis.com/v1/places.q(" + city + "," + countryCode + ")?appid=(appid)";
console.log(woeidUrl);
var woeID = "An error occured retrieving your WOEID.";
Parse.Cloud.run('httpRequest', { url: woeidUrl }, {
success: function(WOEID) {
console.log("returned from http request.");
},
error: function(error) {
console.log("Error occurred while making request for WOEID " + error.message);
status.error(error.message);
}
});
},
{
success: function() {
// results is an array of Parse.Object.
console.log('#Query');
status.success("Updated Records!!");
},
error: function(error) {
// error is an instance of Parse.Error.
console.log('#error');
response.error("Failed to save vote. Error=" + error.message);
}
});
});
Where the job httpRequest is:
Parse.Cloud.define("httpRequest", function(request, response) {
var webpage = "Something went wrong.";
Parse.Cloud.httpRequest({
url: request.params.url,
success: function (httpResponse) {
webpage = httpResponse.text;
webpage = webpage.toString();
response.success(webpage);
},
error: function (error)
{
console.log("Error in http request " + error.message);
response.error(error.message);
}
});
});
now I would expect to be printed would be the, object id of first user, their url, the job running, the message"returned from http request." then repeated another time for the second user and finally the job finishing with the message "Updated Records". but instead I get:
I2014-07-22T15:15:16.013Z] A5hod7qKE3
I2014-07-22T15:15:16.045Z] http:/where.yahooapis.com/v1/places.q(Draper,US)?appid=(appid)
I2014-07-22T15:15:16.053Z] GmuqxpTUpM
I2014-07-22T15:15:16.066Z] http:/where.yahooapis.com/v1/places.q(SaltLakeCity,US)?appid=(appid)
I2014-07-22T15:15:16.082Z] #Query
I2014-07-22T15:15:16.131Z] v385: Ran cloud function httpRequest with:
Input: {"url":"http://where.yahooapis.com/v1/places.q(SaltLakeCity,US)?appid=(appid)"}
Result:
2487610TownSalt Lake CityUnited StatesUtahSalt LakeSalt Lake City40.777561-111.93071740.699890-112.10125740.852951-111.739479511America/Denver
I2014-07-22T15:15:16.141Z] v385: Ran cloud function httpRequest with:
Input: {"url":"'http://where.yahooapis.com/v1/places.q(Draper,US)?appid=(appid)'"}
Result:
http://where.yahooapis.com/v1/schema.rng'" xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:start="0" yahoo:count="1" yahoo:total="11">2393601TownDraperUnited StatesUtahDraper8402040.524139-111.86627240.442921-111.92212740.544361-111.78304349America/Denver
I removed 1 / from both the printing urls so I could posts this because I don't have high enough rep to post more than 2 links. I also have put in my appid into the (appid) so the url does return to me the according woeid from yahoo.com. The problem here being I can't actually get into the success function of the http request job. Any help is greatly appreciated!
EDIT:
I was trying to figure out how to run a job in a for loop but couldn't get it to work. I tried to make a promise and do what Fosco said below, but have had no luck. Here is my code.
for(var i = 0; i < woeIDs.length; i++)
{
console.log("hello");
var weatherURL = "http://weather.yahooapis.com/forecastrss?w=" + woeIDs[i] + "&u=f";
var promise = Parse.Cloud.run('httpRequest', { url: weatherURL }, {
success: function(WOEID) {
console.log("got here");
},
error: function(error) {
console.log("Error occurred while making request for WOEID " + error.message);
status.error(error.message);
}
});
Parse.Promise.when([promise]).then(function() { status.success(); });
}
if I run this code I get a hello twice then the two job calls then the "got here" message once. I have tried adding a return statement to it and with no luck also. Thanks again for all the help!!!
The issue here is that inside the each callback, you need to return the promise from your cloud function call if you want to ensure the tasks complete, and have it wait before going to the next object.
Simplified and using promises:
query.each(function(object) {
...
return Parse.Cloud.run(...);
}).then(function() {
// success
}, function(err) {
// error
});
For looping over a promise-returning function like Parse.Cloud.run:
var promises = [];
for (i = 0; i < 5; i++) {
promises.push(Parse.Cloud.run('...', {}));
}
Parse.Promise.when(promises).then(function() {
// all done
}, function(err) {
// error
});

Couldn't able to remove double quotes from json string

I couldn't able to remove the double quotes from json string. Following is my code.
var values = {};
$.each($('#regForm :input'), function(i, field) {
if (field.name == "submit") {
delete field.name;
} else {
values[field.name] = field.value;
}
});
var json_text = JSON.stringify(values);
var global = JSON.parse(json_text);
console.log(global);
$.ajax({
type : "POST",
dataType : "JSON",
data : global,
url : "http://localhost:8080/SpringRestServices/register",
beforeSend : function(xhr) {
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Accept-Encoding", "utf-8");
xhr.setRequestHeader("Content-type", "application/json");
},
success : function(data) {
alert("success"+data);
console.log("Success:", data);
},
error: function(xhr, textStatus, errorThrown) {
console.log("HI");
alert("Failed to cancel subscription! Message:" + textStatus /*+ jqXHR.errorThrown + xhr.responseText*/);
alert("readyState: " + xhr.readyState);
alert("responseText: "+ xhr.responseText);
alert("status: " + xhr.status);
alert("text status: " + textStatus);
alert("error: " + errorThrown);
}
});
Here is my output when I see it in the firefox debugger:
"{"username":"hi","email":"hi#gmail.com","password":"123"}"
I need the actual result:
{"username":"hi","email":"hi#gmail.com","password":"123"}
Can anyone help me on this.
This is my server code:
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseBody
public RegisterResponse newAccount(#RequestBody Register registration) {
String newAccountSql = "INSERT INTO register (email,password,username) VALUES (:email,:password,:username)";
RegisterResponse regResponse = new RegisterResponse();
regResponse.setResult(-1);
// ServiceDataBean<AuthToken> retBean = new
// ServiceDataBean<AuthToken>();
try {
System.out.println("register service calling.....");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("email", registration.getEmail());
messageDigest = MessageDigest.getInstance("MD5");
byte[] md5 = new byte[64];
messageDigest.update(
registration.getPassword().getBytes("iso-8859-1"), 0,
registration.getPassword().length());
md5 = messageDigest.digest();
namedParameters.addValue("password", convertedToHex(md5));
namedParameters.addValue("username", registration.getUsername());
GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
// TODO what to do with the updInt also check it's not -1
int updInt = jdbcTemplate.update(newAccountSql, namedParameters,
generatedKeyHolder);
regResponse.setResult(0);
System.out.println("from register");
} catch (Throwable e) {
regResponse.setResult(001);
e.printStackTrace();
}
return regResponse;
}
Try
json_text= json_text.slice(1, json_text.length-1);
See if writing your ajax request like this helps. It removes the explicit dataType that I think could be causing you an issue and also removes the beforeSend function and replaces it with the built in contentType option (and removes the explicit return datatype).
$.ajax({
type : "POST",
data : global, //Or json_text, whichever worked.
url : "http://localhost:8080/SpringRestServices/register",
contentType : "application/json",
success : function(data) {
alert("success"+data);
console.log("Success:", data);
},
error: function(xhr, textStatus, errorThrown) {
console.log("HI");
alert("Failed to cancel subscription! Message:" + textStatus /*+ jqXHR.errorThrown + xhr.responseText*/);
alert("readyState: " + xhr.readyState);
alert("responseText: "+ xhr.responseText);
alert("status: " + xhr.status);
alert("text status: " + textStatus);
alert("error: " + errorThrown);
}
});
I dont think there is a need to replace any quotes, this is a perfectly formed JSON string, you just need to convert JSON string into object.This article perfectly explains the situation : Link
Example :
success: function (data) {
// assuming that everything is correct and there is no exception being thrown
// output string {"d":"{"username":"hi","email":"hi#gmail.com","password":"123"}"}
// now we need to remove the double quotes (as it will create problem and
// if double quotes aren't removed then this JSON string is useless)
// The output string : {"d":"{"username":"hi","email":"hi#gmail.com","password":"123"}"}
// The required string : {"d":{username:"hi",email:"hi#gmail.com",password:"123"}"}
// For security reasons the d is added (indicating the return "data")
// so actually we need to convert data.d into series of objects
// Inbuilt function "JSON.Parse" will return streams of objects
console.log(data); // output : Object {d="{"username":"hi","email":"hi#gmail.com","password":"123"}"}
console.log(data.d); // output : {"username":"hi","email":"hi#gmail.com","password":"123"} (accessing what's stored in "d")
console.log(data.d[0]); // output : { (just accessing the first element of array of "strings")
var content = JSON.parse(data.d); // output : Object {username:"hi",email:"hi#gmail.com",password:"123"}" (correct)
console.log(content.username); // output : hi
var _name = content.username;
alert(_name); // hi
}

What's the best way to retry an AJAX request on failure using jQuery?

Pseudo code:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Even better would be some kind of exponential back-off
Something like this:
$.ajax({
url : 'someurl',
type : 'POST',
data : ....,
tryCount : 0,
retryLimit : 3,
success : function(json) {
//do something
},
error : function(xhr, textStatus, errorThrown ) {
if (textStatus == 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status == 500) {
//handle error
} else {
//handle error
}
}
});
One approach is to use a wrapper function:
(function runAjax(retries, delay){
delay = delay || 1000;
$.ajax({
type : 'GET',
url : '',
dataType : 'json',
contentType : 'application/json'
})
.fail(function(){
console.log(retries); // prrint retry count
retries > 0 && setTimeout(function(){
runAjax(--retries);
},delay);
})
})(3, 100);
Another approach would be to use a retries property on the $.ajax
// define ajax settings
var ajaxSettings = {
type : 'GET',
url : '',
dataType : 'json',
contentType : 'application/json',
retries : 3 // <-----------------------
};
// run initial ajax
$.ajax(ajaxSettings).fail(onFail)
// on fail, retry by creating a new Ajax deferred
function onFail(){
if( ajaxSettings.retries-- > 0 )
setTimeout(function(){
$.ajax(ajaxSettings).fail(onFail);
}, 1000);
}
Another way (GIST) - override original $.ajax (better for DRY)
// enhance the original "$.ajax" with a retry mechanism
$.ajax = (($oldAjax) => {
// on fail, retry by creating a new Ajax deferred
function check(a,b,c){
var shouldRetry = b != 'success' && b != 'parsererror';
if( shouldRetry && --this.retries > 0 )
setTimeout(() => { $.ajax(this) }, this.retryInterval || 100);
}
return settings => $oldAjax(settings).always(check)
})($.ajax);
// now we can use the "retries" property if we need to retry on fail
$.ajax({
type : 'GET',
url : 'http://www.whatever123.gov',
timeout : 2000,
retries : 3, // <-------- Optional
retryInterval : 2000 // <-------- Optional
})
// Problem: "fail" will only be called once, and not for each retry
.fail(()=>{
console.log('failed')
});
A point to consider is making sure the $.ajax method wasn't already wrapped previously, in order to avoid the same code running twice.
You can copy-paste these snippets (as-is) to the console to test them
I've had a lot of success with this code below (example: http://jsfiddle.net/uZSFK/)
$.ajaxSetup({
timeout: 3000,
retryAfter:7000
});
function func( param ){
$.ajax( 'http://www.example.com/' )
.success( function() {
console.log( 'Ajax request worked' );
})
.error(function() {
console.log( 'Ajax request failed...' );
setTimeout ( function(){ func( param ) }, $.ajaxSetup().retryAfter );
});
}
Your code is almost full :)
const counter = 0;
$(document).ajaxSuccess(function ( event, xhr, settings ) {
counter = 0;
}).ajaxError(function ( event, jqxhr, settings, thrownError ) {
if (counter === 0 /*any thing else you want to check ie && jqxhr.status === 401*/) {
++counter;
$.ajax(settings);
}
});
None of these answers work if somebody calls .done() after their ajax call because you won't have the success method to attach to the future call back. So if somebody does this:
$.ajax({...someoptions...}).done(mySuccessFunc);
Then mySuccessFunc won't get called on the retry. Here's my solution, which is heavily borrowed from #cjpak's answer here. In my case I want to retry when AWS's API Gateway responds with 502 error.
const RETRY_WAIT = [10 * 1000, 5 * 1000, 2 * 1000];
// This is what tells JQuery to retry $.ajax requests
// Ideas for this borrowed from https://stackoverflow.com/a/12446363/491553
$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
if(opts.retryCount === undefined) {
opts.retryCount = 3;
}
// Our own deferred object to handle done/fail callbacks
let dfd = $.Deferred();
// If the request works, return normally
jqXHR.done(dfd.resolve);
// If the request fails, retry a few times, yet still resolve
jqXHR.fail((xhr, textStatus, errorThrown) => {
console.log("Caught error: " + JSON.stringify(xhr) + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown);
if (xhr && xhr.readyState === 0 && xhr.status === 0 && xhr.statusText === "error") {
// API Gateway gave up. Let's retry.
if (opts.retryCount-- > 0) {
let retryWait = RETRY_WAIT[opts.retryCount];
console.log("Retrying after waiting " + retryWait + " ms...");
setTimeout(() => {
// Retry with a copied originalOpts with retryCount.
let newOpts = $.extend({}, originalOpts, {
retryCount: opts.retryCount
});
$.ajax(newOpts).done(dfd.resolve);
}, retryWait);
} else {
alert("Cannot reach the server. Please check your internet connection and then try again.");
}
} else {
defaultFailFunction(xhr, textStatus, errorThrown); // or you could call dfd.reject if your users call $.ajax().fail()
}
});
// NOW override the jqXHR's promise functions with our deferred
return dfd.promise(jqXHR);
});
This snippet will back-off and retry after 2 seconds, then 5 seconds, then 10 seconds, which you can edit by modifying the RETRY_WAIT constant.
AWS support suggested we add a retry, since it happens for us only once in a blue moon.
Here is a small plugin for this:
https://github.com/execjosh/jquery-ajax-retry
Auto incrementing timeout would be a good addition to it.
To use it globally just create your own function with $.ajax signature, use there retry api and replace all your $.ajax calls by your new function.
Also you could directly replace $.ajax, but you will not be able to make xhr calls without retry then.
Here's the method that worked for me for asynchronous loading of libraries:
var jqOnError = function(xhr, textStatus, errorThrown ) {
if (typeof this.tryCount !== "number") {
this.tryCount = 1;
}
if (textStatus === 'timeout') {
if (this.tryCount < 3) { /* hardcoded number */
this.tryCount++;
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status === 500) {
//handle error
} else {
//handle error
}
};
jQuery.loadScript = function (name, url, callback) {
if(jQuery[name]){
callback;
} else {
jQuery.ajax({
name: name,
url: url,
dataType: 'script',
success: callback,
async: true,
timeout: 5000, /* hardcoded number (5 sec) */
error : jqOnError
});
}
}
Then just call .load_script from your app and nest your success callback:
$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=&region=', function(){
initialize_map();
loadListeners();
});
DemoUsers's answer doesn't work with Zepto, since this in the error function is pointing to Window. (And that way of using 'this' is not secure enough as you don't know how they implement ajax or no need to.)
For Zepto, maybe you could try below, till now it works well for me:
var AjaxRetry = function(retryLimit) {
this.retryLimit = typeof retryLimit === 'number' ? retryLimit : 0;
this.tryCount = 0;
this.params = null;
};
AjaxRetry.prototype.request = function(params, errorCallback) {
this.tryCount = 0;
var self = this;
params.error = function(xhr, textStatus, error) {
if (textStatus === 'timeout') {
self.tryCount ++;
if (self.tryCount <= self.retryLimit) {
$.ajax(self.params)
return;
}
}
errorCallback && errorCallback(xhr, textStatus, error);
};
this.params = params;
$.ajax(this.params);
};
//send an ajax request
new AjaxRetry(2).request(params, function(){});
Use constructor to make sure request is reentrant!
I resolved my specific issue with #vsync 3rd code.
$.ajax = (($oldAjax) => {
var df = $.Deferred();
// on fail, retry by creating a new Ajax deferred
function check(self, status) {
console.log("check " + status + " => " + self.retries);
const shouldRetry = status != 'success' && status != 'parsererror';
if (shouldRetry && self.retries > 0) {
setTimeout(() => {
console.log("retry " + self.retries);
$.ajax(self);
}, self.retryInterval || 100);
}
}
function failed(jqXHR, status, e) {
if (this.retries - 1 <= 0) {
// 재시도 횟수가 끝나면, 오류 보내기
df.reject(KfError.convertKfError(jqXHR, this.url));
} else {
this.retries --;
check(this, 'retry', this.retries);
}
}
function done(res, textStatus, jqXHR) {
if (!res.success) { // 200 코드이지만, 응답에 실패라면 오류로 처리
if (this.retries - 1 <= 0) {
df.reject(KfError.createResponseError(res, this.url));
} else {
this.retries --;
check(this, 'retry', this.retries)
}
} else {
df.resolve(res, textStatus, jqXHR);
}
}
return function (settings) {
$oldAjax(settings)
.fail(failed)
.done(done);
return df;
};
})($.ajax);
function createRequest(url) {
return $.ajax({
type: 'GET',
url: url,
timeout: 2000,
retries: 3,
retryInterval: 1000
});
}
$(function () {
createRequest(Rest.correctUrl('/auth/refres'))
.then((res) => {
console.log('ok res');
})
.catch((e) => {
// Finally catch error after retrial.
console.log(e);
});
});

Categories

Resources