I'm stuck with such thing:
I have var calls update_interval, and I start/stop my intervals with it.
My problem is to understand if interval clear or not.
Smth like:
clearInterval(update_interval);
update_interval = false/null/undefined
is not counting due to the specific of my project.
Any ideas?
Theres is no built-in mechanism to check whether a timeout has completed or not. You will have to do it yourself, here is a minimal example:
var pending = true;
var timer = setTimeout(function() {
/* do some stuff */
pending = false;
}, 5000);
You can then check whether the timed function is done running or not:
if (pending) {
// hasn't run yet
}
else {
// is done running
}
Related
I'm writing a program in Javascript that takes input strings and then runs a simulation on each string. The user decides how fast, i.e. what the delay should be between processing each string. I'm using the setInterval() function to control this. However, I am running into the issue that longer strings may not be ready to process because the last string is still processing. This causes a slew of errors on my part. Here's some code to paint a better picture.
let testingInterval = setInterval(function () {
strprn.innerHTML = `<h2>${strings[i]}<\h2>`; // displays current string to user
if (i + 1 == strings.length) { // checks if should notify user all strings have been processed
checker.finalCheck = true;//the checker uses this flag to notify the user once the test completes
}
checker.check(strings[i]); //runs the check i.e. simulation
i++; // increments the counter iterating through the array (setup code not shown here)
if (i >= strings.length) {
clearInterval(testingInterval); //once we reach the end stop the interval iterating
evenOutResults(); // clean up answers function
updateTimeStamp(Date.now()); // for readability, I add a timestamp of when the results were generated
}
}, delay); // user specified delay
What I'm looking for is a way to honor the delay but also not begin the next call until the current string has finished processing.
Something like this logically (the code below freezes your browser XD):
function delayLoop() {
setTimeout(function () {
strprn.innerHTML = `<h2>${strings[i]}<\h2>`;
if (i + 1 == strings.length){
checker.finalCheck = true;
}
checker.check(strings[i]);
i++;
if (i < strings.length) {
// check if the current string has finished, if so call, else wait until the string is done
while (checker.processingFlag){
// console.log('Waiting for current string to finish');
}
delayLoop(); // call again
} else {
evenOutResults();
updateTimeStamp(Date.now());
}
}, delay);
Correct me if I'm wrong, but it seems like as though you want to have some kind of schedule of appointments that you'd like "messages" to be received at and if a message is not ready at the appointment, then you'd like it to reschedule to the next appointment. You can easily find the next available appointment with some kind of iteration
const nextCheckin = (lastCheckin, interval) => {
while (lastCheckin < Date.now())
last += delay
return last
}
Assuming the order of messages matters you can do something like such
const simulation = (strings, delay) => {
let checkin = Date.now() + delay
for (const str of strings) {
const result = simulate(str)
checkin = nextCheckin(checkin, delay)
console.log(`Waiting for: ${checkin-Date.now()}`)
while (Date.now() < checkin)
continue
reportWork(result)
}
}
The while loop will cause the event loop to hang, so maybe a call to setTimeout would be more appropriate, but whatever floats a boat.
Sorry, I should have clarified this more. Checker.check() is a function that uses a setInterval() to display an animation. The animation needs to be done for a set of objects. Because of the setInterval(), anytime we wait means javascript will try to execute the next lines of code. This means vanilla for-loops are out of the question.
My initial solution was to throw the for-loop iteration itself into a setTimeout(). This works as long as the delay is long enough for all the objects being iterated. Problem is the objects rarely are, so if an object was larger than the one it preceded and the delay was short then the whole animation crashed. In the end, Promises were the easiest solution.
let runLoop = async () => {
for(var i = 0; i < strings.length; i++){
strprn.innerHTML = `<h2>${strings[i]}<\h2>`;
console.log("about to await");
if (i + 1 == strings.length){
checker.finalCheck = true;
}
await new Promise(resolve => checker.check(resolve, strings[i]));
if (checker.finalCheck){
updateTimeStamp(Date.now());
}
}
}
runLoop();
For those who wonder onto this looking for an answer, the await pauses your execution until the resolve is met. You pass resolve onto your function, and inside the setInterval() code block, at the very end you call resolve(). In order to use the await, the whole thing gets wrapped up inside of an async.
i have a javascript application Angular based that runs a while loop after a user press a button it runs the loop until we get a certain number then the loop ends. currently am not able to do anything else on the UI when the loop is running is there a way to push this loop to the background so the user can continue other things on the UI.
Use angular watchers for that:
$rootscope.watch(myParam, function () {});
Or use non-blocking setInterval():
var timer = setInterval(function () {
if (myParam == 'what-i-need') {
clearInterval(timer);
}
}, 200);
You can use webworker, as sample code below (the code is not fully functional but it just to give you an idea.
(
function () {
var scope = self;
var condition = false
scope.addEventListener('message', function (event) {
var caller = event.data;
if(caller.name && caller.command && caller.command === 'TERMINATE'){
return;
}
start(caller);
}, false);
function start(){
while (condition) {
if(condition)
scope.postMessage({result:"result"});
}
}
})();
In your angularjs controller or service
if (!worker) {
worker = new $window.Worker("./online-capability-worker.js");
worker.addEventListener('message', onResponse, false);
}
function onResponse(event) {
var response = event.data;
//This is my nuber returned by worker
}
Javascript is synchronous, while event driven systems allow it to mimic an asynchronous language, your code is still running on a single thread. You could use a setTimeout to recursively call a function rather than use the while loop, that way there is time for the thread to do other things in between each iteration.
function incrementNumber(initial, destination){
if(initial < destination){
setTimeout(function(){incrementNumber(initial+1, destination}), 10);
}else{
alert('We found the number!');
}
}
I would like to point out that I agree with the use of setInterval for something as simple as changing a number, but in browsers (to the best of my knowledge still), the interval is kicked off from the time the callback is initially called, which can cause unexpected results if the callback itself has any significant execution time (say, an ajax call).
I'm trying to run setTimeout() on a website via Firefox's Scratchpad. It seems that there were various Firefox bugs regarding this particular JavaScript method - and it's twin, setInterval(). In Firefox v.56 and the latest Waterfox (both pre-"Quantum"), these JavaScript methods do not seem to work at all. By contrast, in the Firefox "Quantum" versions, it does seem to work... That is, the very same code works in FF "Quantum", which does not work in the immediate pre-"Quantum" versions of Firefox. And yes, I've tried all sorts of variations.
Circumstance has it that I'm stuck with the pre-Quantum version(s) of Firefox for this exercise and I need to find a way to "build" this setTimeout() method from first principles, as it were.
One thought would be to take the current date/time and then loop through a check to see if, say, 10 seconds (or 5 minutes) have passed, before continuing with further code/script execution.
Any ideas how to simulate setTimeout() resource-efficiently with JavaScript but without setTimeout() or setInterval() ?
---EDIT---
False alarm... could get setInterval() to work in the older browsers too; my bad!
(this means the reason for asking the question is gone, but the question as such may remain...)
---2nd EDIT---
Whereas setTimeout() works here:
setTimeout(function(){ alert("Hello"); }, 3000);
it does not work / seems to be ignored here:
i=0;
while(i < 100)
{
// window.open("https://www.cnn.com","_self");
// window.open("https://www.bbc.com","_self");
// setTimeout(function(){ alert("Hello"); }, 3000);
setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000);
setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000);
alert(i);
i++;
}
// security mgr vetoed ???
Why?
If you really-really want to simulate the setTimeout function without blocking the browser and so on, you can try use the requestAnimationFrame function to get some delay. It should work in the Firefox 14.0+. Something like that:
function mySetTimeout (callback, timeout) {
var startTime = performance.now();
function mySetTimeoutRec () {
requestAnimationFrame(function () {
// This way this function will be called
// asynchronously around 60 times per second
// (or less frequently on the inactive tabs).
// We can check that enough time has passed
// and call the user callback or this function again.
var currentTime = performance.now();
var elapsedTime = currentTime - startTime;
if (elapsedTime < timeout) {
mySetTimeoutRec();
} else {
callback();
}
});
}
mySetTimeoutRec();
}
It can be used just like setTimeout:
mySetTimeout(function () { console.log('Howdy.'); }, 10 * 1000);
Anyway you should not try to do something like that in the most cases. If it seems that you are have problems with setTimeout, that's probably something else is wrong.
One possibility would be to take advantage of a network request that takes a variable number of seconds to complete:
function artificialSetTimeout(fn, timeout) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) fn();
}
xhr.open('get', 'https://httpstat.us/200?sleep=' + timeout);
xhr.send();
}
console.log('start');
artificialSetTimeout(() => console.log('end'), 2000);
Don't rely on its timing to be entirely accurate, though.
So far in my tests written in CasperJS, I've been using waitForSelector() on page-specific elements to determine if a page has fully loaded (including all the async ajax requests). I was hoping to come up with a more standard way of waiting for page load and was wondering if the following was possible?
Inject as clientscript the following (include.js)
$(document).ajaxStop(function() {
// Do something
})
Description of ajaxStop according to jquery api: Register a handler to be called when all Ajax requests have completed.
Define a casper.waitForLoad function that when called would wait for the "something" in above code block
Use the function in several parts of the test.
Also any tips on the // Do Something part would also be appreciated :) I was thinking about using the window.callPhantom feature in phantomJS but I'm reading that it's not officially supported in casperjs.
I would do something like this in include.js:
(function(){
window._allAjaxRequestsHaveStopped = false;
var interval;
$(document).ajaxStop(function() {
if (interval) {
clearInterval(interval);
interval = null;
}
interval = setTimeout(function(){
window._allAjaxRequestsHaveStopped = true;
}, 500);
});
$(document).ajaxStart(function() {
window._allAjaxRequestsHaveStopped = false;
if (interval) {
clearInterval(interval);
interval = null;
}
});
})();
This sets a (hopefully unique) variable to the window object that can be later retrieved. This also waits a little longer incase there is another request after the previous batch ended.
In CasperJS you would probably do something like the following to wait for the change in the request status. This uses adds a new function to the casper object and uses casper.waitFor() internally to check the change.
casper.waitForAjaxStop = function(then, onTimeout, timeout){
return this.waitFor(function(){
return this.evaluate(function(){
return window._allAjaxRequestsHaveStopped;
});
}, then, onTimeout, timeout);
};
And use it like this:
casper.start(url).waitForAjaxStop().then(function(){
// do something
}).run();
or this:
casper.start(url).thenClick(selector).waitForAjaxStop().then(function(){
// do something
}).run();
I have loading animation which displays while the webpage is loading in the background. Once loading is complete it disappears.
What I'd like...
1. The animation to appear for a minimum of 1 second.
2. Once the 1 second minimum has expired, the animation will be naturally removed following page loading.
3. To avoid the possibility of a fault (and watching an endless animation loop), I want the animation to time out if it takes more than 5 seconds to load.
Here's what I have so far...
$(window).load(function()
{
$('#followingBallsG').hide();
$('#backgroundcolor').hide();
});
Any assistance you can provide would be greatly appreciated. Thanks.
There are no built-in jQuery features for this. You will need to write out the logic for this. Here is a simple implementation, free of race-conditions.
(function(){
var didDone = false;
function done() {
//Prevent multiple done calls.
if(!didDone)
{
didDone = true;
//Loading completion functionality here.
$('#followingBallsG').hide();
$('#backgroundcolor').hide();
}
}
//Variables to keep track of state.
var loaded = false;
var minDone = false;
//The minimum timeout.
setTimeout(function(){
mindone = true;
//If loaded, fire the done callback.
if(loaded)
{
done();
}
}, 1000);
//The maximum timeout.
setTimeout(function(){
//Max timeout fire done.
done();
}, 5000);
//Bind the load listener.
$(window).load(function(){
loaded = true;
//If minimum timeout done, fire the done callback.
if(minDone)
{
done();
}
});
})();
I've wrapped it in a immediately invoked function expression and assumed $(window).load is the event you are listening for. It should be easy to adapt this to another event or to run at another time if this is not the desired effect.