How to set up a timeout and ontimeout for XMLHttpRequest? - javascript

At the moment I am using a similar code visible below to set a specific value for timeout when creating an instance of XMLHttpRequest.
I also set a function for ontimeout which will be executed when event is fired.
I would like to know if it is possible to set a timeout value globally for any XMLHttpRequest and a global function when ontimeout is called.
I am aware I could use a factory for XMLHttpRequest which could set timeout and ontimeout automatically on each instance created but I would like to know if a different approach exists.
Notes: I am looking for a solution based on vanilla JavaScript (no jQuery or other libraries) and I am targeting only Chrome and FireFox latest version.
Any idea is welcome thanks.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);
xhr.timeout = 2000;
xhr.onload = function () {};
xhr.ontimeout = function (e) {
// do smt here
};
xhr.send(null);

You have at least three options:
Encapsulate your use of XMLHttpRequest in your own function. That lets you apply these sorts of things in that function. The fact your code uses the function makes it perfectly clear what's going on. For instance:
function createXHR() {
var xhr = new XMLHttpRequest();
xhr.timeout = 2000;
xhr.addEventListener("timeout", function(e) {
// ...
});
return xhr;
}
Override XMLHttpRequest with your own version. I do not recommend doing this, but sometimes if you need to integrate with code that uses XMLHttpRequest directly, you may feel you need to do it. Example:
(function() {
var realXMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function fakeXMLHttpRequest() {
realXMLHttpRequest.apply(this, arguments);
this.timeout = 2000;
this.addEventListener("timeout", function(e) {
// ...
});
};
XMLHttpRequest.prototype = realXMLHttpRequest.prototype;
})();
Again, I do not recommend it, but it's possible.
You've said below that the one above doesn't work for you. If it doesn't, it's because the XMLHttpRequest implementation you're using is making life difficult. This workaround will work:
(function() {
var realXMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function fakeXMLHttpRequest(arg) {
var xhr;
if (typeof arg !== "undefined") {
// Some implementations allow for a non-standard argument, support them
xhr = new realXMLHttpRequest(arg);
} else {
// Normal case
xhr = new realXMLHttpRequest();
}
xhr.timeout = 2000;
xhr.addEventListener("timeout", function(e) {
// ...
});
return xhr;
};
XMLHttpRequest.prototype = realXMLHttpRequest.prototype;
})();
That works even though you call it with new XMLHttpRequest because the way the new operator works is that it creates an object and calls the function with that object as this, and then the result of new is that object unless the function returns a different non-null object, as the one above does.
Did I mention I do not recommend this? ;-)
Use a library that already does #1 for you.

I was able to monkey path XMLHttpRequest using the following code.
(function (xhr) {
var send = xhr.send;
xhr.send = function (data) {
this.timeout = 5000;
var hasTimeOut = 'ontimeout' in this;
if (hasTimeOut) {
this.ontimeout = function () {
throw ('Error XMLHttpRequest timeout.');
};
}
return send.apply(this, arguments);
};
})(XMLHttpRequest.prototype);

Related

Can one use the Fetch API as a Request Interceptor?

I'm trying to run some simple JS functions after every request to the server with the Fetch API. I've searched for an answer to this question, but haven't found any, perhaps due to the fact that the Fetch API is relative recent.
I've been doing this with XMLHttpRequest like so:
(function () {
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
this.addEventListener('load', function () {
someFunctionToDoSomething();
});
origOpen.apply(this, arguments);
};
})();
Would be great to know if there's a way to accomplish this very same global thing using the Fetch API.
Since fetch returns a promise, you can insert yourself in the promise chain by overriding fetch:
(function () {
var originalFetch = fetch;
fetch = function() {
return originalFetch.apply(this, arguments).then(function(data) {
someFunctionToDoSomething();
return data;
});
};
})();
Example on jsFiddle (since Stack Snippets don't have the handy ajax feature)
Just like you could overwrite the open method you can also overwrite the global fetch method with an intercepting one:
fetch = (function (origFetch) {
return function myFetch(req) {
var result = origFetch.apply(this, arguments);
result.then(someFunctionToDoSomething);
return result; // or return the result of the `then` call
};
})(fetch);

understanding event handling and callbacks in javascript

I was messing around with IndexedDB and I realised that I don't really get event handling in JavaScript.
So here's the code:
var request = indexeddb.open(bla, version);
request.onsuccess = function (event) { };
So the open-method returns a IDBOpenDBRequest object, which, according to Mozillas site, inherits from IDBRequest, which apart from properties and methods also has event handlers, one of them being onsuccess:
https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest.onsuccess
So on the mozilla site, onsuccess is just function () { }
Now, when the database was opened sucessfully, the "onsuccess" event fires and the appropiate event handler is called, in this case the function that I defined. But how exactly does that happen?
The request variable contains an instance of the IDBOpenDBRequest. So when I write request.onsuccess = somefunction(), am I overwriting the default function of the IDBRequest-class?
I dont get why I can write request.onsuccess = somefunction(event) { } and how the event is passed to that function.
EDIT:
function myObect() {
this.open = function(a,b,c) {
if (c > 20) {
this.success("String");
}
};
};
var myrequest = new myObect();
myrequest.open(4,2,21);
myrequest.success = function (ev) {
console.log(ev);
};
To create a similar api, you can do something like:
function open(a, b, c) {
var request = {};
if(c > 20) {
setTimeout(function() {
if(typeof request.success === "function") {
request.success("String");
}
}, 1);
}
return request;
}
var myrequest = open(4, 2, 21);
myrequest.success = function(ev) {
console.log(ev);
};
Here, setTimeout is asynchronous so the callback function is not executed immediately. When any asynchronous task is run in JavaScript, the currently executing code will run to completion before any callback is called. So success is guaranteed to be set before request.success called.
The Indexed DB open call similarly runs an asynchronous task, and then dispatches events when it is finished which will eventually call your callback function.
I overwriting the default function of the IDBRequest-class
Looks like there is no default behavior, so you just set up your own func.

Making variables available outside a function without globals

I'm struggling to get my head around how to pass information around in javascript. Can some kind person show me how to take a variable from within a function and use it in another function but without making the variable global. I think i need to use return but I am stuck and not sure what to google to get something I can learn from.
For example, how can I make the "json" variable available so i can use it in the "MasterView" function. Thank you in advance.
function fetchData() {
var xhr = Ti.Network.createHTTPClient({
onload : function(e) {
Ti.App.Properties.setString('cachedJson', this.responseText);
var json = JSON.parse(Ti.App.Properties.getString('cachedJson',''));
},
timeout: 5000
});
xhr.open("GET", site_url + "?get_json=postObjects");
xhr.send();
}
function MasterView() {};
There are numerous ways to go around this without using globals.
Also, what do you mean by "without making the variable global"?
You want to avoid polluting the global namespace or you just don't want your variable to be available in all of your functions?
Here's a way of passing the value from one of your functions to another:
function a(){
var hello = "world";
return hello;
}
function b(){
var result = a();
console.log(result);
}
As you can see function a() returns the variable hello with the value "world".
Now if you call function b() it will store a()'s return value in a variable called result and then log it to the console.
Another option is to use parameters (sometimes called as arguments) in your functions:
function a(){
var hello = "world";
b(hello);
}
function b(arg){
console.log(arg);
}
In this case if you will call function a() it will instantly call function b(), passing the variable hello, so b() will log "world".
Of course the latter aproach is not always a good choice, i.e. you simply don't want your first function to call another one. In that case you can do the following:
function a(){
var hello = "world";
return hello;
}
function b(arg){
console.log(arg);
}
Then call function b() as: b(a());
This way you'll pass function a()'s return value as an argument to function b().
Hopefully this cleared up most of your questions. :)
// Simply add this:
var json;
// and continue...
function fetchData() {
var xhr = Ti.Network.createHTTPClient({
onload : function(e) {
Ti.App.Properties.setString('cachedJson', this.responseText);
json = JSON.parse(Ti.App.Properties.getString('cachedJson',''));
},
timeout: 5000
});
xhr.open("GET", site_url + "?get_json=postObjects");
xhr.send();
}
function MasterView() {
console.log(JSON.stringify(json))
};
With hopes that it might work...Or:
function fetchData() {
var xhr = Ti.Network.createHTTPClient({
onload : function(e) {
Ti.App.Properties.setString('cachedJson', this.responseText);
json = JSON.parse(Ti.App.Properties.getString('cachedJson',''));
},
timeout: 5000
});
xhr.open("GET", site_url + "?get_json=postObjects");
xhr.send();
}
function MasterView() {
var json;
fetchData();
console.log(JSON.stringify(json))
};
Global variables are useful for a lot of things, however if the only variable you need is json, and you only need it in the function Masterview, call the function fetchData from the function MasterView and make fetchData return json.
W3 schools is a great tool for javascript and html development. Try this link for more on functions, specifically functions with a return value.
http://www.w3schools.com/js/js_functions.asp

Anomaly in setInterval function in asynchronous functions calls in Javascript

Below is the snippet of the code I am preparing to build a website.
<script type="text/javaScript">
function h(d) {
console.log("hello");
return;
};
function func(callback) {
var httpRequest; // create our XMLHttpRequest object
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// Internet Explorer old versions
httpRequest = new
ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.onreadystatechange = function() {
// inline function to check the status
if (httpRequest.readyState === 4 &&
httpRequest.status === 200) {
callback(httpRequest.responseText);
// call the callback function
}
};
httpRequest.open("GET", '/try_ajax',true);
httpRequest.send();
}
// call the function
setInterval(func(h), 10000); // Timer is triggered here
</script>
Interestingly, though I have set the interval at 10 seconds, in my console the "hello" is appearing only once. But it should keep appearing after 10 seconds. Please help!
this is wrong
setInterval(func(h), 10000); // Timer is triggered here
You are saying take whatever is returned from func(h) and assign it to the timeout
setInterval(function(){func(h);}, 10000); // Timer is triggered here
You are actually calling the function in your setInterval call, which is not what you want. You should only give a reference to it and put parameters as the last arguments, like this:
setInterval(func, 10000, h); // Timer is triggered here
I'd like to give a shoutout to some who pointed out that the OP wanted additional parameters with his callback, something that I completely missed in my initial answer.
Fact of the matter is - when you do
setInterval(func(h), 10000)
return value of func(h) is called every 10 seconds. Your func(h) returns void. Therefore in effect after the first call, there is nothing to call for the setInterval function. Therefore you see the first invokation and nothing after that!

How to transfer another parameter with an ajax state change

I have the following code in my ajax query:
xhr.onreadystatechange = stateChange;
and the function stateChange is function stateChange(event)
Is it possible to add a second parameter to the function so it doesn't just passes a number as well as the event?
I've tried doing xhr.onreadystatechange = stateChange(event,'123'); with function stateChange(event,num) but it doesn't seem to work.
You can create a closure that allows your event handling function access to those variables.
Instead of
xhr.blahblah;
xhr.onreadystatechange = stateChange;
xhr.blahblah;
This technique creates an anonymous function that gives scope to your '123' variable:
xhr.blahblah;
function (xhrObj, callbackFn, param) {
xhrObj.onreadystatechange = function (event) {
callbackFn(event, param);
};
}(xhr, stateChange, '123');
xhr.blahblah;
Mmmm, sort of:
xhr.onreadystatechange = function(event) { stateChange(event,'123'); };
would do what you say you want, but it isn't clear to me that what you say you want is what you need.

Categories

Resources