I write a polling script to receive newly created data records. I want to execute the call in every N seconds.
I tried setTimeout() and setInterval() to run the polling asynchronously, but both freeze the browser while executing the Polling() function, which is really strange for me.
I call the StarPolling() function when the page is loaded. APICall() function is a jQuery $.POST function which is working well - and async - in any other situations.
This is the code I use with setTimeout()
var pollinginterval = 5000;
function StartPolling()
{
setTimeout(Polling, pollinginterval);
}
function Polling()
{
[... some code ...]
var api_call = 'API_URL';
var api_call_parameters = {
[...]
};
APICall(api_call, api_call_parameters, function(json_response)
{
/* this is the callback belongs to the $.POST request */
[... some code ...]
setTimeout(Polling, pollinginterval);
});
}
The version I tried using setInterval() is very similar except the recursive call.
I can not use Workers or HTML5 sockets for this because cross-browser support is a must.
Is there any way to run the polling in a REAL asynchronous way, or using a new 'thread' with JavaScript without freezing the browser?
UPDATE:
This is how the APICall() operates:
function APICall(call, parameters, success_callback)
{
$.post(apibase + "" + call,parameters)
.done(function(response){
try
{
var json_response = $.parseJSON(response);
}
catch(error)
{
[...]
}
if(json_response.header.status == "OK")
{
success_callback(json_response);
}
else if(json_response.header.status == "error")
{
[...]
}
})
.fail(function(error) {
[...]
});
}
UPDATE: I am testing the polling with a normal and private browser (firefox) window at the same time to try the functionality. I just noticed, that the problem only occurs when both windows are running the polling simultaneously.
Maybe it is a firefox bug...
The OP is wanting to run Polling in such a way that it doesn't interfere with the main thread (i.e. in a background thread). The only way to do this is to use a WebWorker, which he specifically doesn't want to use.
For a bunch of interesting reading see the W3 document about event loops, but basically everything that happens in the browser is single threaded. All javascript will happen on the main thread (except for web workers). All setTimeout and setInterval do is queue a callback that will get run in the main thread after ~x seconds.
So sorry, there isn't any other way beside web workers.
You may use a long polling pattern like this :
(function Polling() {
setTimeout(function() {
$.ajax({ url: "server", success: function(response) {
//your try/catch here
}, dataType: "json", complete: Polling });
}, 5000);
})();
So the poll will attempt to finish before to restart, even if the server job is quite long...
Related
If you have web messages which trigger a function and the messages are coming in quickly, can the function be executed before the previous is finished?
document.addEventListener('some_message', some_func, false);
function some_func (data){
//Is the code here always executed before the next function is executed?
}
Since there's only a single Javascript thread running, only one piece of code can run at a time. So this will always execute in the same order as events are triggered, and only one at a time:
function callback_func(data) {
alert(data);
}
However, if your callback works asynchronously, i.e. yields the thread back to the browser, then it's unpredictable:
function callback_func(data) {
setTimeout(() => {
// who knows when this will be called ¯\_(ツ)_/¯
alert(data);
}, Math.random());
}
Yes, that is the way asynchronous events work in JavaScript.
You can check out this article, which explains how async-await works in modern JavaScript.
I made a CMS which during operation pulls large amounts of data.
CMS is made in PHP, MySQL, jQuery, Bootstrap and use AJAX.
The problem is if you lose your internet connection can cause problems on displaying and scrolling.
I would love if there is a good way to show the error and blocks all functions on the site when there is no internet connection. When the connection is established it should be all function allowed on the site.
Thanks!
(Sorry for my bad English.)
If you are using jQuery, you can just hook on the global error handler and lock up your application when an error occurs. The lock up screen could simply ask to try again.
$( document ).ajaxError(function() {
// lock your UI here
});
Also, once the UI is locked, you could execute a function that would ping your server in an Exponential Backoff fashion and automatically unlock the application on network restore.
Locking your app can easily be done with jQuery's blockUI plugin.
Example
(function ($) {
var locked = false;
var errorRetryCount = 0;
var blockUiOptions = { message: "Oops! Could not reach the server!" };
// change this function to adjust the exponential backoff delay
function backoff(n) {
return Math.pow(2, n) * 100;
}
$(function () {
$( document ).ajaxError(function () {
var req = this;
errorRetryCount += 1;
if (!locked) {
locked = true;
$.blockUI(blockUiOptions);
}
// retry to send the request...
setTimeout(function () { $.ajax(req); }, backoff(errorRetryCount));
}).ajaxSuccess(function () {
locked && $.unblockUI();
locked = false;
errorRetryCount = 0;
});
});
})(jQuery);
Note: You may not want to retry indefinitely your request upon network failure, and would want to quit retrying at some point. Since this is out of the scope of this question, I'll leave it as it is. However, you may take a look at this related question, which may help you sort this part out.
If you're using jQuery already, you could create a simple ajax call to your server, and if it fails within a couple of seconds, either your server or the clients internet connection is down.
Something like this:
setInterval(function() {
$.ajax({
url: "https://cms.example.com/ping",
})
.fail(function( data ) {
alert('Connection lost?');
// remember do to something smart which shows the error just once
// instead of every five seconds. Increasing the interval every
// time it fails seems a good start.
});
}, 5*1000);
Using plain JavaScript and simple code:
window.navigator.onLine ? 'on' : 'off'
It supports by almost every browser, please check Can I use
edit: re-read your question and misunderstood my first pass through so this wouldn't be valid for continuous monitoring... but i'll leave it here anyways as it may be useful for someone else.
i would suggest loading a small js file that adds a class to an element of your page and then checking if that class is applied after the fact... assuming you are using jQuery
file on the remote server loaded into your page after jQuery via script tag
$('html').addClass('connected');
local code
if($('html').hasClass('connected')) {
// connected
} else {
// not connected
}
In my application in a particular page I use an AJAX function call continuously like below,
<script type="text/javascript">
$(document).ready(function(){
setInterval(function() {
$.ajax({
url:'clmcontrol_livematchupdate',
type:'post',
dataType: 'json',
success: function(data) {
$('#lblbattingteam').html(data.battingnow);
$('#lblscore').html(data.score);
$('#lblwickets').html(data.wickets);
$('#lblovers').html(data.overs);
$('#lblballs').html(data.balls);
$('#lblextras').html(data.extras);
$('#lblrr').html(data.runrate);
$('#lblbowlingteam').html(data.bowlingnow);
$('#lblbowler').html(data.currentbowler);
$('#lblbowlerovers').html(data.bowlerovers);
$('#lblbowlerballs').html(data.bowlerballs);
$('#lblrunsgiven').html(data.runsgiven);
$('#lblextrasgiven').html(data.extrasgiven);
$('#lblwicketstaken').html(data.wicketstaken);
$('#lblecon').html(data.econ);
}
});
}, 4000);
});
</script>
Any how at the first attempts the application ran well and the values got updated as I expected, but after few attempts more the values struggled to update and going further updates were not happening. Is it because the function slows down the system due to continuous ajax calls?
It's better not to use setInterval() because If the first request hasn't completed and start another one, you could end up in a situation where you have multiple requests that consume shared resources and starve each other. You can avoid this problem by waiting to schedule the next request until the last one has completed.
Just Try:
(function ajaxInterval() {
$.ajax({
url:'clmcontrol_livematchupdate',
type:'post',
dataType: 'json',
success: function(data) {
$('#lblbattingteam').html(data.battingnow);
$('#lblscore').html(data.score);
$('#lblwickets').html(data.wickets);
$('#lblovers').html(data.overs);
$('#lblballs').html(data.balls);
$('#lblextras').html(data.extras);
$('#lblrr').html(data.runrate);
$('#lblbowlingteam').html(data.bowlingnow);
$('#lblbowler').html(data.currentbowler);
$('#lblbowlerovers').html(data.bowlerovers);
$('#lblbowlerballs').html(data.bowlerballs);
$('#lblrunsgiven').html(data.runsgiven);
$('#lblextrasgiven').html(data.extrasgiven);
$('#lblwicketstaken').html(data.wicketstaken);
$('#lblecon').html(data.econ);
},
complete: function() {
// Schedule the next request when the current one has been completed
setTimeout(ajaxInterval, 4000);
}
});
})();
There is a potential issue here that would be obvious if you checked your network calls from a debugger. Due to the non blocking async behavior of the ajax call you have the potential to be making simultaneous ajax calls. Depending on your browser you are only allowed to make so many calls at the same time so they will queue up. In these circumstances there are also no guarantees of execution order.
In your situation I would set async: false in the ajax options. You are already gaining non interface blocking behavior by executing in the setInterval callback. Since setInterval just applies a timer in between method calls you will never have more than one ajax call operating at a given time(which is a likely culprit of your issue).
I'm trying to return a variable only after it has been set within a setTimeout callback. I couldn't think of any other way to do this, but here's my attempt (I know the code seems silly, but it's to work around a Cordova bug). For reasons beyond my understanding, it results in an infinite loop.
function isConnected() {
var done = false;
setTimeout(function() {
done = true;
}, 500);
while (!done) {}
return navigator.connection.type!== Connection.NONE;
}
Can anyone explain to me why this is happening, or provide an alternative?
Update (solution):
function isConnected(callback) {
setTimeout(function() {
callback(navigator.connection.type !== Connection.NONE);
}, 500);
}
isConnected(function(connected) {
if (!connected)
alert('Not Connected');
});
You simply can't solve your problem that way. Because javascript is single threaded, the setTimeout callback can only run when your JS thread of execution finishes so with your infinite loop, it will never get to run and your code will hang. Eventually the browser will complain about a long-running piece of JS and offer to shut it down.
Instead, you need to use a callback function on the setTimeout() and continue your code from that callback. You can't use sequential code for timeouts. You must use asynchronous coding styles.
You could do something like this where you pass in a callback and it calls the callback back and passes it the connected boolean:
function GetConnectedState(callback) {
setTimeout(function() {
callback(navigator.connection.type !== Connection.NONE);
}, 500);
}
Your existing code doesn't seem to offer anything other than a look at the connection state in 1/2 second. With any real sort of asynchronous operation in javascript (such as an ajax call or a websocket connection), there should also be a success or completion callback that will tell you when/if the operation actually completes and you can also trigger the callback based on that (sooner than 1/2 second most of the time). So, this doesn't really look like a complete solution, but it's all you show us you're using.
For example, here's an answer you can look at that calls a callback when an images loads successfully, with an error or times out with no response: Javascript Image Url Verify and How to implement a "function timeout" in Javascript - not just the 'setTimeout'. A similar concept could be used for implementing your own timeout on some other type of asynchronous call.
As I revisit this 5 years later, can't help but to offer up a fancier alternative:
await new Promise(function(resolve) {
setTimeout(resolve, 500);
});
if (navigator.connection.type === Connection.NONE) {
alert('Not Connected');
}
Javascript is single-threaded. The timeout function can't run until your script returns to the main event loop. But as long as you're in the while loop it will never return, so the timeout function never runs, so done is never set to true.
It's not possible in Javascript to wait for an asynchronous event before returning.
Consider I have multiple (sometimes more than 12) ajax calls that are calling every 2 seconds or more. Data gathered through the calls are set to the UI contained elements (Like progress bars). After all I have delay on SCROLL while timers working . This delay is natural, But How can I handle it?
NOTE: Calls Destinations are services that provides data with the minimum spent time. The point that makes the scroll sad, is using multiple setTimeout() and setInterval() methods. To get more familiar with my work, See the below code:
function FillData(accessUrl, name) {
var add = accessUrl;
$.support.cors = true;
if (add) {
$.ajax({
type: 'GET',
url: accessUrl,
crossDomain: true,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (data) {
Update(name, data);
},
error: function (xhr, status, error) {
LogResponseErrors(status , error, name);
}
});
setTimeout(function () { FillData(accessUrl, name); }, interval);
//Consider that the method calls with different parameters one time and it will run automatically with setTimeout
}
else {
freezeFrame(name);
}
}
Used Tags explains what I used.
Any useful answer will be appreciated
From what I understand in your question. You have delay when you're handling your ajax responses and you need to remove the delay.
Javascript is single-threaded. Therefore, if there is a function that takes long time to complete, it could dominate the thread and cause the UI not responding. To deal with this, you have 2 options:
Optimize your code so that the function does not take long.
Use setTimeout to break your function into smaller pieces. For example: if your function is executing a loop of 100 items, you could break it to execute 10 times with 10 items each.
Update: (based on updated question):
It seems that the loop never stops when you use setTimeout like this. Should have something like:
counter++;
if (counter <= 12)
setTimeout(function () { FillData(accessUrl, name); }, interval);
Due to timing problem between ajax and your setTimeout, at some points, there are a lot of events (escalated) waiting in the queue to be executed and cause performance problem. Try putting your setTimeout inside your success or complete function