I have the below code:
sendRequest : function(data){
var me = this;
this._createData(data);
try{
this.req.open(this.method,this.page,true);
this.req.onreadystatechange=function()
{
if (this.readyState==4 && this.status==200)
{
if(this.responseText)
var response = eval('(' + this.responseText + ')');
else
response = null;
me.callBack(response);
return false;
}
}
this.req.send(this.data);
} catch(err){
me.callBack(response);
}
},
It works fine, and returns what I expect it to return, but when the connection is lost, it doesn't go into the catch block. What I want to know is how catch the request when server page is not available.
Here's an example from Microsoft's doc page for onreadystatechange:
function reportStatus()
{
if (oReq.readyState == 4 /* complete */) {
if (oReq.status == 200 || oReq.status == 304) {
alert('Transfer complete.');
}
else {
// error occurred
}
}
}
var oReq = new XMLHttpRequest();
oReq.open("GET", "http://localhost/test.xml", true);
oReq.onreadystatechange = reportStatus;
oReq.send();
Look where it says // error occurred.
There is a similar code example on this MDN documentation page.
I set a setTimeout before I send the Ajax call:
var timeout = window.setTimeout("functionToCallOnTimeout()", 2000);
inside functionToCallOnTimeout I stop the call:
oReq.current=null;
On a positive answer I clear the timeout:
timeout = null;
Related
I'm working on a firefox extension and using browser.webRequest.onBeforeRequest.addListener.
I need to redirect or release the webRequest until I have information back from calls made within the handler.
I used to use synchronous ajax, but the page was blocked for too long when the network was poor. If the request time exceeds 5 seconds, I want to cancel the ajax request. But it seems impossible to set a timeout on a synchronous call.
These days I try to use asynchronous ajax and use the methods(return new Promise) provided in https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onBeforeRequest. I tried several days but failed.
My codes:
var LOOKUP_URL = "https://a.b.c.com/";
var urlLookup = new UrlLookup(LOOKUP_URL);
var blockList = [];
browser.webRequest.onBeforeRequest.addListener(redirectAsync, {urls: ['<all_urls>']},, ["blocking"]);
function redirectAsync(details) {
var url = details.url;
return new Promise(function(resolve,reject){
var urlLookupResult = urlLookup.check(url, LookupComplete);
if(urlLookupResult.result){
var redirectUrl = urlLookupResult.url;
resolve({redirectUrl})
}
})
}
function LookupComplete(url, data, error){
if(data.result){
blockList.push(url);
localStorage.setItem("blockList",JSON.stringify(blockList));
return {
result: true,
url: "https://aaa.bbb.com/alerts.php?url=" + url;
}
}else {
return null
}
}
codes in urlLookup.js:
function UrlLookup(domain) {
function check(url, callback) {
var data;
var http_request = new XMLHttpRequest();
var timeId = window.setTimeout(function(){
http_request.abort();
},5000)
http_request.open("GET", domain + 'url='+url);
try {
http_request.send();
http_request.onreadystatechange = function(){
if(http_request.readyState == 4 && http_request.status == 200){
window.clearTimeout(timeId);
data = JSON.parse(http_request.response);
return callback(url, data);
}
}
} catch (e){
return callback(url, null, "Error");
}
};
return {
check: check
};
}
How should I modify it?
I generally have been using XMLHttpRequest to perform Ajax calls. However, when the server has an error, I'd like to console.log the error so that I don't have to run to the server to see the event log there.
Here's what I generally do:
function LoadPage(){
var parameters="this=that";
var x = new GetXmlHttpObject();
x.open("POST", "Ajax.aspx?Function=LoadPage")
x.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
x.ontimeout = function () { location.reload(true); }
x.send(parameters);
x.onreadystatechange = function () {
if (x.readyState === 4 && x.status === 200){
//Do Stuff with the response
}
}
But if the server has an error with the request, I get the error on the x.send(parameters) line. I've tried to wrap that in a try..catch, but the error comes up in the console even with the command held inside the try.
How can I console.log the 500 errors from the server using this structure?
But if the server has an error with the request, I get the error on the x.send(parameters) line.
That won't happen. The client can't react to the response in any way before the response has arrived.
I've tried to wrap that in a try..catch
That won't work for two reasons.
It is asynchronous
It doesn't throw an exception
if (x.readyState == 4 && x.status == 200){
You're already testing for a 200 status here. Test for a 500 status in the same way.
Updated function
function LoadPage() {
return new Promise(function(succeed, fail) {
var req = new XMLHttpRequest();
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.open("POST", "Ajax.aspx?Function=LoadPage", true);
req.ontimeout = function () { location.reload(true); }
req.addEventListener("load", function() {
if (req.status < 400)
succeed(req.responseText);
else if (req.status == 500)
fail("Error 500: Internal Server Error");
else
fail(new Error("Request failed: " + req.statusText));
});
req.addEventListener("error", function() {
fail(new Error("Network error"));
});
req.send("this=that");
});
}
Usage:
LoadPage().then(function(text) {
console.log("data.txt: " + text);
}, function(error) {
console.log("Failed to fetch data.txt: " + error);
});
I'm trying to get a webworker to poll a web server interface on the same machine every second or so. Most articles I have read say to avoid setInterval and use setTimeout instead but I have yet to find an example that uses AJAX instead of Jquery.
The code I have so far is below:
(function poll() {
setTimeout(function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newContent = '';
newContent += responseObject.cmd;
console.log(newContent);
}
}
xhr.open('GET', 'http://localhost:8194/screen_update/1000', true);
xhr.send(null);
setTimeout(poll, 1000);
}, 1000);
})();
The preferred output would be to poll the server each second which should in theory be more than adequate for the response to come through. I only want one request on the go at a time so if I end up with a request taking more than a second it just dumps the request (rather than queuing it) and issues a new request.
The above code polls okay but doesn't complete for 2 seconds so I've obviously got my setTimeout mixed up somewhere. Where do I correct this code?
I did just that a few days ago.. and while it may not be the most elegant, it works fine so far.
I have the worker handle the timeout / check interval, not the main JS. So I guess that's one more thing that the UI doesn't need to handle. Here is my worker code:
function checkStatus() {
console.log("statusCheck started");
var ajaxRequest;
try { ajaxRequest = new XMLHttpRequest(); // Opera 8.0+, Firefox, Safari
} catch (e) { try { // Internet Explorer Browsers
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) { try {
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) { // Something went wrong
console.error("AJAX not possible");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function() {
if(ajaxRequest.readyState == 4) {
self.postMessage(ajaxRequest.responseText);
var timer;
timer = self.setTimeout(function(){
checkStatus();
}, 1000);
}
}
ajaxRequest.open("GET", "/worker_statusCheck.php", true);
ajaxRequest.send(null);
}
this.onmessage = function(e){
checkStatus(); // the message comes in just once on pageLoad
};
Define a variable that determines if ajax finished or not. If function is called while ajax hasn't finished yet, you can exit the function and wait for the next call.
var stillWorking = false;
(function poll() {
if(stillWorking) return false;
stillWorking = true;
setTimeout(function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.readyState == 4) stillWorking = false;
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newContent = '';
newContent += responseObject.cmd;
console.log(newContent);
}
}
xhr.open('GET', 'http://localhost:8194/screen_update/1000', true);
xhr.send(null);
setTimeout(poll, 1000);
}, 1000);
})();
You can call same function when you get response of AJAX. In this way no need to check that currently AJAX is in process or not.
function poll() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange= function() {
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newContent = '';
newContent += responseObject.cmd;
console.log(newContent);
}
if (xhr.readyState == 4)
{
setTimeout(function(){ poll();},1000);
}
}
xhr.open('GET', 'http://localhost:8194/screen_update/1000', true);
xhr.send(null);
};
setTimeout(function(){ poll();},1000);
If you want to use onload callback then callback code should be
xhr.onload= function() {
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newContent = '';
newContent += responseObject.cmd;
console.log(newContent);
}
setTimeout(function(){ poll();},1000);
}
Because you are using HTML5 WebWorker, probably, you can use window.fetch which uses promises (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), I think that browser support is almost the same.
Here is an example:
((url, INTERVAL, configs) => {
const MAX_ERRORS = 4;
let errors = 0;
var poll = () => window.setTimeout(getData, INTERVAL);
function getData() {
return window
.fetch(url, configs)
.then(res => res.json())
.then(data => {
errors = 0;
poll();
return data;
})
.then((data) => {
console.log("new data available", data);
})
.catch(() => {
if(errors >= MAX_ERRORS) {
console.log("GIVING UP");
return;
}
errors += 1;
return poll();
})
;
}
return poll();
})("http://jsonplaceholder.typicode.com/posts/1", 1000, {
method: 'GET'
});
I'm making an http request asynchronously using XMLHttpRequest:
xhr.open(method, uri, true);
When I send something:
xhr.send(something)
When the server is down, it throws the following error:
net::ERR_CONNECTION_REFUSED
How can I catch and handle this error? The standard try..catch block doesn't work as the request is asynchronous.
Thanks in advance.
Use the onerror event of the XMLHttpRequest:
function aGet(url, cb) {
var x = new XMLHttpRequest();
x.onload = function(e) {
cb(x.responseText)
};
x.onerror= function(e) {
alert("Error fetching " + url);
};
x.open("GET", url, true);
x.send();
}
var dmp = console.log.bind(console); // Dummy callback to dump to console
aGet("/", dmp) // Ok, uses onload to trigger callback
aGet("http://dgfgdf.com/sdfsdf", dmp); // Fails, uses onerror to trigger alert
I wrote a full solution to that problem. It works perfectly!
I have a function called networkOrfail which will try to resend the XMLHttpRequest each second, if the network is available. Otherwise, it'll ignore the request.
When the request is succeeded, that polling stops and the response is returned.
Here's how to detect whether the network is available:
function getNavigatorConection() {
return navigator.onLine;
}
Then, create your XMLHttpRequest:
function makeRequest() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'anypage/anotherpage', true);
xhr.timeout = 2000;
xhr.onload = function () {
// Your request is completed
if (xhr.readyState == 4 && xhr.status == 200) {
// You're in a successfully condition
}
};
xhr.ontimeout = function (e) {
// Your request timed out
};
xhr.send(null);
}
Now, define your polling method as follows:
function networkOrFail(callFunc, callTime) {
let connected = getNavigatorConection();
let callableTimes = callTime < 2000 ? 2000 : callTime;
let toursBegin = 3;
let tours = toursBegin;
let intervalId;
let request = function() {
intervalId = setInterval(function() {
let connected = getNavigatorConection();
if (tours > 0) {
if (connected) {
callFunc();
tours =0;
return false;
}
tours--;
alert("i tryied againt to resend for another time and it remain just "+tours+" to retry");
} else {
clearRequest();
tours =toursBegin;
}
}, callableTimes > 5000 ? 5000 : callableTimes);
};
let clearRequest = function() {
clearInterval(intervalId);
intervalId = null;
};
if (connected)
callFunc();
else
request();
}
Finally, call the send method through the polling method by passing it toghether with the timeout in minutes:
networkOrFail(makeRequest, 5000);
Ok, I've created a working javascript ajax file, but it generates an absurd number of these dom exceptions. I'm not sure why that is, because from what I can see, all the elements I call are currently still in existance.
The code is here:
window.onload = function(){init();}
function init() {
ajax = ajaxInit();
setInterval(function(){ajaxContact(ajax);},2000);
ajaxContact(ajax);
ajax.onreadystatechange = function() {update(ajax);}
}
function ajaxInit() {
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
}
if (ajax) {
document.getElementById("status").innerHTML = "AJAX initialized";
return ajax;
}
else {
docuement.getElementById("status").innerHTML = "Error: AJAX not available";
return false;
}
}
function ajaxContact(ajax) {
try {
ajax.open("GET","updateAjax.php?" + "ran=" + Math.random(),true);
ajax.send();
}
catch (err) {
alert(err.message);
document.getElementById("status").innerHTML = "Error contacting server";
document.getElementById("loading").src = "images/redx.png";
}
}
function update(ajax) {
if (ajax.readyState==4 && ajax.status==200){
dataObj = eval('(' + ajax.responseText + ')');
document.getElementById("status").innerHTML = dataObj.status;
document.getElementById("frameNumber").innerHTML =
"Frame:" + dataObj.firstFrame + "/" + dataObj.lastFrame;
document.getElementById("thumbnail").src = dataObj.imgSrc;
}
if (ajax.status==404) {
document.getElementById("status").innerHTML = "Ajax updater not found";
document.getElementById("loading").src = "images/redx.png";
}
}
You are probably trying to call open and send on ajax, but it throws errors if the request has not finished within the two seconds between each call by setInterval. You need to check in each call whether the ajax object has been sent already or is ready for opening (check ajax.readyState).
In Chrome, the line
if (ajax.status==404) {
causes the error by accessing the status before ajax.readyState is HEADERS_RECEIVED (2), LOADING (3), DONE (4). Try making it
if (ajax.readyState == 4 && ajax.status==404) {
to make sure that the object is ready before accessing the status.