I have the following JS code:
var delay = 5000;
function init() {
setInterval(getFileCount, delay);
}
function getFileCount() {
$.get('/notification/course-file-count', function(response) {
if (response.items.length === 0) {
return false;
}
// Do stuff with response
});
}
On page load I'm calling the init() function. The idea is to start the interval and call the getFileCount() function every 5 seconds.
So, the interval waits 5s after the page loads and runs, but it always makes the Ajax call twice.
What am I missing?
UPDATE:
I know the init() function is triggered twice on page load (thanks to the comment by Yury Tarabanko). I don't quite understand, why. The almost-full code:
$(function() {
'use strict';
function handleCourseNotification() {
var delay = 5000;
function init() {
setInterval(getFileCount, delay);
}
function getFileCount() {
$.get('/notification/course-file-count', function(response) {
if (response.items.length === 0) {
return false;
}
updateCourseList(response.items);
});
}
function updateCourseList(items) {
// update course list...
}
return {
init: init
};
}
if ($('#js-auth-course-list').length) {
var notificationHandler = handleCourseNotification();
notificationHandler.init();
}
});
It's a small module, which I initialize after page load, if a specific element is available in the DOM - $('#js-auth-course-list'). Why is init called 2 times actually? I directly call it once.
In general, it is not a good idea to call asynchronous calls inside a setInterval() because you do not know the exact response time. So, you could end up calling the second async function before the response from the first call has returned.
You can try with setTimeout() like this:
var delay = 5000;
var async = function() {
$.get('/notification/course-file-count', function(response) {
if (response.items.length === 0) {
return false;
}
// Do stuff with response
// Call the async function again
setTimeout(function() {
async();
}, delay);
});
}
async();
Related
How would I execute code not from a string? Here is an example:
var ready = false;
executeWhen(ready == true, function() {
console.log("hello");
});
function executeWhen(statement, code) {
if (statement) {
window.setTimeout(executeWhen(statement, code), 100);
} else {
/* execute 'code' here */
}
}
setTimeout(function(){ready = true}, 1000);
Could I use eval();? I don't think so, I think that's only for strings.
You call it with code().
You need to change statement to a function as well, so it will get a different value each time you test it.
And when you call executeWhen() in the setTimeout(), you have to pass a function, not call it immediately, which causes infinite recursion.
var ready = false;
executeWhen(() => ready == true, () =>
console.log("hello"));
function executeWhen(statement, code) {
if (!statement()) {
window.setTimeout(() => executeWhen(statement, code), 100);
} else {
code();
}
}
setTimeout(function() {
ready = true
}, 1000);
I think there is an easy solution for this, but for some reason I am not getting the expected results. My functions look like this:
var functionA = function(callback) {
loadData(fromURL1); // takes some time
loadData(fromURL2); // takes some time
callback(); // Should be called AFTER the loadData() functions are finished
}
var myCallBackFunction = function() {
// this function is called AFTER functionA() is finished
alert("All my loaded data from URL1 and URL2");
}
window.onload = function() {
functionA(myCallBackFunction);
}
Unfortunately, the callback() function above doesn't wait for loadData() to finish, and then just calls the alert with empty data.
I read a lot of online examples, but I think I am still missing something obvious.
If the loadData()s are async operations, you can do two things:
Using $.ajaxComplete():
var functionA = function(callback) {
loadData(fromURL1); // takes some time
loadData(fromURL2); // takes some time
$.ajaxComplete(function () {
callback(); // Should be called AFTER the loadData() functions are finished
});
}
Or chaining the functions:
var functionA = function(callback) {
loadData(fromURL1, function () {
loadData(fromURL2, function () {
callback(); // Should be called AFTER the loadData() functions are finished
}); // takes some time
}); // takes some time
}
We are using JQuery in our single page application.
Our boostrapper is the starting point for the app and looks like this:
define('homebootstrapper',
['jquery', 'config', 'homerouteconfig', 'presenter', 'dataprimer', 'binder'],
function ($, config, homeRouteConfig, presenter, dataprimer, binder) {
var
run = function () {
$('#busyIndicator').activity(true);
$.when(dataprimer.fetch())
.done(function () {
// $('#busyIndicator').activity(false);
});
};
return {
run: run
};
});
The dataprimer being called looks like this:
define('dataprimer',
['ko', 'datacontext', 'config'],
function (ko, datacontext, config) {
var logger = config.logger,
fetch = function () {
return $.Deferred(function (def) {
console.log('in deferred');
$.when(LongTimeProcessing())
.pipe(function () {
logger.success('Fetched data');
})
.fail(function () { def.reject(); })
.done(function () { def.resolve(); });
}).promise();
};
return {
fetch: fetch
};
});
function LongTimeProcessing(options) {
console.log('in when');
return $.Deferred(function (def) {
var results = options;
for (var i = 0; i < 10; i++) {
var x = i;
$('#counter').html(x);
}
def.resolve(results);
}).promise();
}
The line $('#busyIndicator').activity(true);
should display a progress animation based on SVG or VML. This works well, except when using the JQuery $.when
With this sample code we've tried to create a method that will take some time and is called 'LongTimeProcessing' (instead of an ajax call to the backend which is normally used through amplify)
We see that when we use jquery, the busyindicator doesn't work (read: is not displayed) until the dataprimer returns with def.resolve(). This when seems to block all UI updates. Also, the counter value from the LongTimeProcessing method only shows the last value from this loop. It is executed but it is never visible.
What are we doing wrong? How should we handle this.
You MUST yield to the event processing loop to allow the UI to update and to process outstanding events. This only happens when your own code has finished executing.
Your LongTimeProcessing function does not do this, it starts a loop and doesn't return control to the browser until that loop has finished.
You could achieve what you want by using setTimeout to handle the loop iteration:
function LongTimeProcessing(options) {
console.log('in when');
return $.Deferred(function (def) {
var results = options;
var i = 0;
(function iterate() {
$('#counter').html(i);
if (i < 10) {
++i;
setTimeout(iterate, 250);
} else {
def.resolve(results);
}
})();
}).promise();
}
The call to setTimeout allows the function to terminate immediately after the first call to iterate(), allowing the browser's event processing loop to process UI updates, and then going into the next iteration when the timer elapses.
I have assigned 5000 ms to Settimeout but it is executing before assigned time interval.Can any body explain why it is happening.
<script type="text/javascript">
var getcallback = {
closure: function (callback, functionparam) {
return callback.call(functionparam);
}
}
var cleartimeout;
var startSlideShow = {
timerid: 5000,
startAnimation: function () {
cleartimeout = setTimeout(getcallback.closure(function () {
alert("this is a basic example of chaining methods");
this.startAnimation();
},this), this.timerid);
},
stopAnimation:function(){
}
}
startSlideShow.startAnimation();
</script>
Because getcallback.closure() is executing the function right away, you are not storing a reference to a function to call at a later time.
As soon as you call startAnimation, you're calling getcallback.closure, which immediately calls the callback function. To use setTimeout correctly, you need to either have closure return a function, or not use such a strange thing, and instead just use an anonymous function.
Something along the lines of:
var getcallback = {
closure: function (callback, functionparam) {
return function() {
callback.call(functionparam);
};
}
}
...
Or, to be cleaner, just:
var cleartimeout;
var startSlideShow = {
timerid: 5000,
startAnimation: function () {
cleartimeout = setTimeout(function () {
alert("this is a basic example of chaining methods");
this.startAnimation();
}, this.timerid);
},
stopAnimation:function(){
}
}
startSlideShow.startAnimation();
Ok. here's the scenario:
function DataFeed(){
function PopulateData()
{
$('div#example').load('http://www.example.com', fxnCallBack);
};
function fxnCallBack()
{
PopulateData();
}
this.activator = function() {
PopulateData();
}
};
var example_obj = new DataFeed;
example_obj.activator();
In the above code, the ajax .load gets executed once, then callback executes. But the callback doesn't start the ajax function again?
Thanks in advance.
edit- why doesn't it display new line properly -.-
InternalError: too much recursion
JavaScript engines normally have a max limit in the number of recursions or the time recursive execution may take. Use setInterval instead:
function DataFeed() {
var interval;
function PopulateData() {
$('div#example').load('http://www.example.com', function(data) {
if(data == "clear_interval")
interval = clearInterval(interval); // clear the interval
});
}
this.activator = function() {
interval = setInterval(PopulateData, 1000); // run every second
};
}
var example_obj = new DataFeed();
example_obj.activator();