i have this function:
<script language="javascript">
function live(){
var d = $live;
var elm = document.getElementById("live");
if(d==1){
elm.style.display = 'block';
} else{
elm.style.display = 'none';
}
}
</script>
setInterval(function(){live();},10000);
and im just concerned about my page getting stuck after having it open on the browser for a while or causing my users browser to stop responding or anything like that. How safe is to use loops like this?
Is this what google or facebook use to show new notifications alerts on their page in real time? That seems to go pretty smoothly.
Thank you.
This isn't a loop in the traditional sense, it's really just a function which is called at a regular interval, so you are in the clear here. Just be careful that nothing increases the memory use each time it executes, as that is what will most likely be what will kill the user's browser.
Also, the setInterval needs to me in a script tag, otherwise it will show up on your page.
Use of setInterval is a common practice for showing notifications on websites. It wont hang your page, although you must clear the interval once it is no longer required. Say you have already shown the notification, so better hold the reference of setInterval so that you could clear it later.
var ref = setInterval(fn, 100);
clearInterval(ref);
Related
According to this question, when we set the window.location, javascript will "stop" executing or turn into a race condition.
Sometimes we need to fire window.location = SOMESCH://xxx multiple times inside a WebView to send "Notifications" back to our app. For example setting window.location = myapp://loginButtonEnabled?e=1 to tell the app that the user had filled in some nessasary info and can start login. It seems to be impossible to do something like this:
function(){
window.location = myapp://loginButtonEnable?e=1;
window.location = myapp://hideHintView;
.....
window.location = myapp://theLastThing;
}
Only the last window.location = myapp://theLastThing will be fired and then the execution of Javascript will stop(though we stopped the redirecting in our app by returning NO in webView:shouldStartLoadWithRequest:navigationType:).
I found it interesting that PhoneGap made this possible by using a dispatching queue, but I still haven't figure out why it works, anybody knows the trick??
BTW, is there a simple way to "resume" the execution after setting location? It will be much better than using an operation queue.
You need to give the event loop a chance to respond to the location change each time. The typical way of doing this is using a setTimeout with a small/zero delay, which has the effect of moving execution to the next event loop tick. Try something like this:
var q=[];
function dequeue() {
window.location='myapp://'+q.shift();
if (q.length>0) setTimeout(dequeue,0);
}
function notifyApp(cmd) {
q.push(cmd);
if (q.length==1) setTimeout(dequeue,0);
}
notifyApp('loginButtonEnable?e=1');
notifyApp('hideHintView');
notifyApp('theLastThing');
As for javascript execution stopping, setting window.location shouldn't have this effect unless it actually results in a page change - perhaps try using the technique above and see if your javascript continues after the last notifyApp() call.
EDIT: Another approach to this issue is to create temporary iframes instead of changing the location of the current page - see for example
Triggering shouldStartLoadWithRequest with multiple window.location.href calls
I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.
I am trying to intercept the window.location changes to do some native work in Android app. To ve more specific, I overwrite the call in WebViewClient:
public boolean shouldOverrideUrlLoading(WebView view, String url)
to look for anything start with "native://". The JavaScript code is like this.
function callNative() {
window.location = "native://doSomeNativeWork()";
}
function callNativeManyTimes(count) {
for(i = 0 ; i < count ; i ++) {
callNative();
}
}
DoSomeNativeWork<br/>
The problem I am seeing is that if I call "window.location = something" many time very quickly (like in the code above) , I will only get one call inside the WebViewClient on the native code side. If I make the call 50ms apart, I will get everyone of them. I am thinking that the browser is doing some optimization around this.
I think I can solve this problem like this: do not use window.location, change to embed a native object to javascript, and call methods on that object in javascript. I am just wondering why this is happening. Can someone more familiar wit JS to share some insight?
Thanks
I had exact the same problem. You can do that by creating iframes. I create iframes with the native urls and then I delete the iframe after 2 seconds just so we don't have too many laying around on the DOM. Worked like a charm to me. You can create as many iframes as you want.
I also included a cache buster on the iframe url, even though I'm not sure it's needed. Better safe then sorry.
function callNative(url){
var _frame = document.createElement('iframe');
_frame.width=0; _frame.height=0;_frame.frameBorder=0;
document.body.appendChild(_frame);
if (url.indexOf('?') >= 0){
url = url + "&cb=";
}else{
url = url + "?cb=";
}
_frame.src = url + Math.round(Math.random()*1e16);
// Remove the iframe
setTimeout(function(){document.body.removeChild(_frame);}, 2000);
}
function callNativeManyTimes(count) {
for(i = 0 ; i < count ; i ++) {
callNative('native://doSomeNativeWork()');
}
}
DoSomeNativeWork<br/>
Note that I used the approach above on iOS. Not sure if it's exactly the same on Android, but from judging the question and other answer I guess it's the same.
I would guess that loading a URL is asynchronous (it would probably be a bad idea to block the execution of a script until a URL has been resolved). As such, setting window.location will presumably only queue up the loading of the new URL, which will be done in a different thread.
Waiting 50ms is a hack that may or may not work. You need to find a different approach. You need something that guarantees that each one of those URLs will be resolved. If the order doesn't matter, you could just use images, like somebody suggested. Otherwise, you could use a native JavaScript interface (which is probably the better approach).
I have some code that I'd like to run on a page. My problem is that I don't want it to be run more than once at any one point. It can run multiple times, but just not while another instance of itself is running. I'm using jQuery and loading ajax content.
I just need something that prevents users from clicking hundereds of times and building up the que and pinging my server heaps.
Is this possible?
Thanks.
If it's just the one function being called in different areas, sounds like you're just wanting some sort of basic semaphore test, e.g:
isRunning = false;
function whatever() {
if (!isRunning) {
isRunning = true;
$.ajax(...., function() {
isRunning = false;
});
}
}
This question looks slightly related.
RE your edit: It's also worth noting that whatever javascript solution you put in place here to avoid a barrage of requests should additionally be considered on the server side.
Just keep a variable to flag whether it's running or not:
var running = true;
... complete: function() { running = false; }
I think it would be more user-friendly if you disabled your controls for the time the ajax request is on its way.
This way not only would you be saved from mass clicking, but also the user would know that there is no point in killing the mouse.
I'm making a webpage with dynamic content that enters the view with AJAX polling. The page JS occasionally downloads updated information and renders it on the page while the user is reading other information. This sort of thing is costly to bandwidth and processing time. I would like to have the polling pause when the page is not being viewed.
I've noticed most of the webpages I have open spend the majority of their time minimized or in a nonviewed tab. I'd like to be able to pause the scripts until the page is actually being viewed.
I have no idea how to do it, and it seems to be trying to break out of the sandbox of the html DOM and reach into the user's system. It may be impossible, if the JS engine has no knowledge of its rendering environment. I've never even seen a different site do this (not that the user is intended to see it...)
So it makes for an interesting question for discussion, I think. How would you write a web app that is CPU heavy to pause when not being used? Giving the user a pause button is not reliable, I'd like it to be automatic.
Your best solution would be something like this:
var inactiveTimer;
var active = true;
function setTimer(){
inactiveTimer = setTimeOut("stopAjaxUpdateFunction()", 120000); //120 seconds
}
setTimer();
document.onmouseover = function() { clearTimeout ( inactiveTimer );
setTimer();
resumeAjaxUpdate();
}; //clear the timer and reset it.
function stopAjaxUpdateFunction(){
//Turn off AJAX update
active = false;
}
function resumeAjaxUpdate(){
if(active == false){
//Turn on AJAX update
active = true;
}else{
//do nothing since we are still active and the AJAX update is still on.
}
}
The stopAjaxUpdateFunction should stop the AJAX update progress.
How about setting an "inactivity timeout" which gets reset every time a mouse or keyboard event is received in the DOM? I believe this is how most IM programs decide that you're "away" (though they do it by hooking the input messages at the system-wide level)
I've looked at that problem before for a research project. At the time (2-3 years ago) I did not find a way to get information from the browser about whether or not you are minimized :(
First check when the window loses and gains focus.
window.onblur = function () { /* stop */ };
window.onfocus = function () { /* start */ };
Also, for various reasons, the user may stop reading the page without causing it to lose focus (e.g. he gets up and walks away from the computer). In that case, you have to assume after a period of inactivity (no mouse or keyboard events) that the users' attention has left the page. The code to do that is described in another answer.
I know you've already accepted an answer but I'd personally use a combination of several of the answers mentioned here for various reasons, including:
Using mouse events only alienates users proficient at keyboard based browsing.
Using blur/focus events don't allow for users who go make a cup of tea ;-)
I'd most likely use something like the following as a guideline:
var idleTimer, userIsIdle, pollingTimer;
document.onkeydown = document.onmousemove = resetTimer;
window.onload = function () {
pollingTimer = window.setTimeout(runPollingFunction, 30000);
resetTimer();
/* IE's onblur/onfocus is buggy */
if (window.navigator.appName == "Microsoft Internet Explorer")
document.onfocusin = resetTimer,
document.onfocusout = setIdle;
else
window.onfocus = resetTimer,
window.onblur = setIdle;
}
function resetTimer() {
if (userIsIdle)
setBack();
window.clearTimeout(idleTimer);
idleTimer = window.setTimeout(setIdle, 120000); // 2 minutes of no activity
}
function setIdle() {
userIsIdle = true;
window.clearTimeout(pollingTimer); // Clear the timer that initiates polling
window.clearTimeout(setIdle);
}
function setBack() {
userIsIdle = false;
runPollingFunction(); // call the polling function to instantly update page
pollingTimer = window.setTimeout(runPollingFunction, 300000);
}
You can listen for mousemove and keypress events. If one of those has been fired in the past X seconds, then continue with your updating. Otherwise, don't update.
It's not perfect, but I think it's the best you can do with pure JS.
If you want to venture into the world of Flash, Silverlight, or Java, you may be able to get more information from the browser.