How to solve webkitRequestAnimationFrame giving extremely high FPS - html

Today I've been trying to get myself acquainted with anything new HTML5 has to offer, in particular the canvas. I came upon the site www.html5canvastutorials.com and began following some of the tutorials and playing around with the code a bit in different browsers. When I got to the following example I noticed something odd in google chrome. http://www.html5canvastutorials.com/advanced/html5-canvas-oscillation-animation/
The webkitRequestAnimationFrame function is supposed to help reduce FPS (and thus CPU costs) when not actively on the site, for example when you go to a different tab. However, when I tried the example, I noticed that this does not always appear to give pleasant results.
Google Chrome as active window, site on current tab: Get around 60
FPS, great!
Google Chrome as active window, on a different tab: Get
around 1 FPS, very good.
Google Chrome as active window, on my TV
(used as second monitor), 120 FPS, odd, but no complaints.
Google Chrome not as active window, but on a different tab, also around 1
FPS or so, perfect.
Then the bad part:
If my site is on the current tab, but I have another window completely covering the google chrome window (say a maximized window for example), the FPS shoots up to around 2500 (and consequently maxes one CPU core).
Everything works perfectly normal when I try the same site in Firefox.
This fiddle's an example where it shows the average FPS since the last refresh: http://jsfiddle.net/kmKZa/55/
(I pretty much copied the code from the tutorial site)
I would like to know how I can prevent these scary CPU spikes if anybody has any ideas. Thanks in advance for any advice!

One possible solution is to simply cancel the AnimationFrame loop when you blur the window, and request it again when you refocus it.
var isPaused = false,
animFrame;
loop();
$(window)
.on('focus', function() {
if( isPaused ) {
isPaused = false;
loop();
}
})
.on('blur', function() {
cancelRequestAnimationFrame( animFrame );
isPaused = true;
});
function loop() {
//your crazy loop code
animFrame = requestAnimationFrame( loop );
}

RAF automatically stop execution on "idle".
U don't need to stop RAF loop execution

Related

speechSynthesis.speak not working in chrome

I'm using chrome Version 55.0.2883.87 m (64-bit) on Windows 10.
The following simple html file reproduces the problem and is extracted from my more complex app. It is supposed to speak the 3 words on page load. It works on MS Edge and Firefox but does not work on chrome. This code was working for me on Chrome no problem a couple weeks back.
<html>
<head>
<script lang="javascript">
window.speechSynthesis.speak(new SpeechSynthesisUtterance("cat"));
window.speechSynthesis.speak(new SpeechSynthesisUtterance("dog"));
window.speechSynthesis.speak(new SpeechSynthesisUtterance("bark"));
</script>
</head>
<body></body>
</html>
I may never know for sure, because this problem was intermittent, but it seemed to go away after I started to cancel right before speak.
utter = new window.SpeechSynthesisUtterance("cat");
window.speechSynthesis.cancel();
window.speechSynthesis.speak(utter);
I don't think the cancel necessarily has to come between the utterance object creation and use. Just that it come before every speak. I may have had a different problem as I was only creating one utterance object, not a bunch. I did only see it on Chrome 78. Using Windows 7, 64-bit. Never saw the problem on Firefox or Edge.
EDIT 2 weeks later. No recurrences after several dozen tries. It seems .cancel() solved my problem. My symptoms were: calling speechSynthesis.speak() in Chrome would sometimes not start the speech. There were no immediate indications of a problem in the code, speechSynthesis.speaking would be true and .pending would be false. There would be no events from the utterance object. Normally, when speech would work, I'd get a 'start' event about 0.1 seconds after calling .speak().
speechSynthesis.speak() is no longer allowed without user activation in Google's Chrome web browser since 2018. It violates autoplay policy of Google Chrome. Thus Google Chrome has managed to revoke it's autoplay functionality but you can make use of it by adding a button to make a custom call.
You can visit here to check the status provided by chrome itself also below is the image attached which clearly shows that speechSynthesis.speak() call is prohibited without user's permission.
Link to image
Link to article by Google Chrome
To add to this, the issue for me was the playback rate on the instance of SpeechSynthesisUtterance was above 2. I discovered it must be set to 2 or less in chrome (although it works with higher rates in other browsers like safari).
In chrome, if the utterance rate is above 2, it causes the window.speechSynthesis to be stuck, and needs window.speechSynthesis.cancel() before it will play audio again (at a valid rate below 2) via .speak().
Did your text to voice tryout work only once? Here is why.
In chrome you have to cancel the speechSynthesis, otherwise its not compliant to googles autoplay policy. So you should start your script with:
window.speechSynthesis.cancel()
To cancel any speech synthesis that happened before.
resultsDisplay = document.getElementById("rd");
startButton = document.getElementById("startbtn");
stopButton = document.getElementById("stopbtn");
recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition)();
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.maxAlternatives = 5;
recognition.onresult = function(event) {
resultsDisplay.innerHTML = "You Said:" + event.results[0][0].transcript;
};
function start() {
recognition.start();
startButton.style.display = "none";
stopButton.style.display = "block";
}
function stop() {
recognition.stop();
startButton.style.display = "block";
stopButton.style.display = "none";
}
.resultsDisplay {width: 100%; height: 90%;}
#stopbtn {display: none;}
<div class="resultsDisplay" id="rd"></div>
<br/>
<center>
<button onclick="start()" id="startbtn">Start</button>
<button onclick="stop()" id="stopbtn">Stop</button>
</center>
Try
utterance = new SpeechSynthesisUtterance("cat, dog, bark");
speechSynthesis.speak(utterance);
I made a Weave at LiveWeave.
Instead of specifying the text while calling new, you could try specifying an object with rate, volume, and text separately, and then converting it to voice.

Phaser sound stops working only on Chrome for Android

The sound works for the first few minutes but after a while .play() doesn't play any sound. It seems like if there is a huge duration where no sound has played the sound stops working.
It works fine on Desktop, iOS and the generic android browser. I'm just running into this problem specifically on android devices using mobile chrome as the browser.
This turns out to be a Chrome bug that causes web audio to stop playing sounds if no sound has played for something like 30 seconds.
https://code.google.com/p/chromium/issues/detail?id=518863
The fix seems to be to watch
audioContext.currentTime
and when it gets stuck after 30 secs create a new audioContext.
The solution I ended up using is as follows:
Note I am using the phaser library - so this exact solution wont work for you - but it will give you the general idea
//This is run using a timer event every second
//this.game.time.events.loop(1000, this.checkAudioContext, this);
evil.AudioManager.prototype.checkAudioContext=function(){
//work out when the audio context has stopped
if(this.game.sound.context.currentTime-this.last_context_time===0){
//close out the existing context and create a new one
//you will also need new gain nodes if you are using them
this.game.sound.context.close();
this.game.sound.context=new AudioContext();
this.game.sound.masterGain= this.game.sound.context.createGain();
this.game.sound.masterGain.gain.volume=this.volume;
this.game.sound.masterGain.connect(this.game.sound.context.destination);
//now go through every sound and connect them to the new context
//creating gain nodes as we go.
for(var key in this.tracks){
var snd=this.tracks[key].snd;
snd.context=this.game.sound.context;
snd.masterGainNode = this.game.sound.masterGain;
snd.gainNode=this.game.sound.context.createGain();
snd.gainNode.gain.value = snd.volume * this.volume;
snd.gainNode.connect(snd.masterGainNode);
}
}else{
//update out time variable
this.last_context_time=ctx.currentTime;
}
}
What version of phaser and android do you have? For me it seems to play without issues for a 4-minute song i tried. Even if the screen goes of, it continues without any problem when it is resumed. A dirty solution will be to add an loop that plays a silent sound every 2 minutes for example just to "refresh" the sound manager if that solves your problem.

Chrome idle extension for kiosk environment with notification and browsing data reset

I've written a skeleton Chrome extension for a Library kiosk environment. The purpose of the extension is to clear all browsing data and restart Chrome after X seconds of inactivity. I was inspired by the Idle Reset extension on the Chrome web store, but this doesn't provide all features I'd like. Ideally I would like to mimic Presto-based Opera's inactivity reset, present in kiosk mode, where a dialogue window with a countdown is displayed, i.e.:
Inactivity reset
The browser will be reset and all browsing data removed in 60...1 seconds
But I think that's maybe a bit too complicated and I'm not sure whether the chrome.notification API supports dynamic content such as countdown timers.
So far I have come up with some code that displays a chrome notification after 1 minute of inactivity. The notification informs the user the browser will be reset in 30 seconds unless activity is resumed. The notification then closes itself. After a further 30 seconds of inactivity, the browsing data is cleared, any existing tabs removed and a new tab opened. I am using the chrome.alarms API and lowering the chrome.idle.setDetectionInterval after the first idle event. If the user resumes activity the alarms and notifications are cleared, and chrome.idle.setDetectionInterval is restored to the default value of 60 seconds.
Here is my event.js code:
chrome.idle.onStateChanged.addListener(function (newState) {
if (newState == "idle") {
var opt = {
type: "basic",
title: "Web Browser about to be reset",
message: "Web browser has been inactive for 1 minute. Move the mouse or type something within 30 seconds to prevent the reset.",
iconUrl: "refresh-icon.png"
};
chrome.notifications.create("browserResetNotification", opt, function() {
chrome.idle.setDetectionInterval(15);
chrome.alarms.create("inactivityAlarm", {'when': Date.now() + 30000})
});
}
else {
chrome.alarms.clear("inactivityAlarm", function() {});
chrome.notifications.clear("browserResetNotification", function() {});
chrome.idle.setDetectionInterval(60);
}
});
chrome.alarms.onAlarm.addListener(function (alarm) {
if (alarm.name == 'inactivityAlarm') {
chrome.browsingData.remove({
}, {
"appcache": true,
"cache": true,
"cookies": true,
"downloads": true,
"fileSystems": true,
"formData": true,
"history": true,
"indexedDB": true,
"localStorage": true,
"pluginData": true,
"passwords": true,
"webSQL": true
});
chrome.tabs.create({
url: "http://myurl.com",
active: true
}, function (newtab) {
chrome.tabs.query({}, function (results) {
for (var i = 0; i < results.length; i++) {
var tab = results[i];
if (tab.id != newtab.id) {
chrome.tabs.remove(tab.id);
}
}
});
});
}
})
My questions
I've been testing my code and have found it's not altogether reliable (i.e. the notification/reset doesn't always occur), and TBH I'm not surprised. Is there a better approach?
Is it possible to display a chrome notification for a fixed duration rather than have it open and close of its own accord? I'd like to have it show for the full 30 seconds up to the point the alarm fires and the browser resets.
I am confused about the chrome.idle API, in particular when to use chrome.idle.queryState method versus when to use chrome.idle.onStateChanged event. In particular it would be nice to be able to query the state at that very moment without having to provide a detectionIntervalInSeconds, required by the method.
What does chrome.notifications.clear method actually do? Signal to Chrome that any record of a notification should be removed? Or force a notification to be removed from the user's display? I'm unclear on when it'd be appropriate to use it.
It's not good to lump questions together on SO, but I'll try to reply.
First off, some background info on notifications.
A notification can be shown on screen (which normally happens when it's created), or hidden in the notification center of Chrome (the bell icon in the system tray). In either case it's still "open". Chrome automatically moves notifications there after a bit of time (that depends on the priority property).
Now, to your questions.
I've been testing my code and have found it's not altogether reliable (i.e. the notification/reset doesn't always occur), and TBH I'm not surprised.
The notification does not re-appear if you try to reuse the notification ID without closing the notification first. It is then updated in-place in the notification center and not re-shown. So if you are reusing the ID and want it to appear again, clear before create.
The alarm might not go off because the minimum granularity for chrome.alarms API is 1 minute. If you need lower granularity, you'll need to use DOM setTimeout (which is not compatible with event pages if you use one).
Is it possible to display a chrome notification for a fixed duration rather than have it open and close of its own accord? I'd like to have it show for the full 30 seconds up to the point the alarm fires and the browser resets.
Not easily, no. Like I said, the time it's shown on-screen depends on the priority, but even high-priority notifications don't last forever and the exact timing is not documented. However, this leads to the existence of the priority update trick.
In your case, you may have better luck with Web Notifications API. They look simpler, but will do the job in your particular use case. The upside is that they never disappear on their own.
I am confused about the chrome.idle API, in particular when to use chrome.idle.queryState method versus when to use chrome.idle.onStateChanged event. In particular it would be nice to be able to query the state at that very moment without having to provide a detectionIntervalInSeconds, required by the method.
The difference is between the question "As of this moment, have the user been idle in the last N seconds?" and asking Chrome "Tell me as soon as user has been idle for N seconds". They both have their use, but in your case you probably want to react to events.
By the way, in your code calling chrome.idle.setDetectionInterval(15) makes no sense. As soon as input happens when your current state is idle the event will fire - it does not matter how long it was idle for before.
It can actually break your logic completely (maybe that's the reason your code is unreliable) if that makes Chrome reconsider the idle state.
What does chrome.notifications.clear method actually do? Signal to Chrome that any record of a notification should be removed? Or force a notification to be removed from the user's display? I'm unclear on when it'd be appropriate to use it.
chrome.notifications.clear does the same as clicking the X on the notification itself - closes it, as opposed to hiding. This makes the ID no longer refer to a notification - so a new one will be created if you reuse the ID. It also triggers the onClosed event. If the notification is displayed on screen at this point, it will be immediately removed.
If you're looking at the message center when clear is called, the weirdest thing happens - the notification ceases to exist from your code's perspective, but is still visible until the message center is closed.
And finally..
Is there a better approach?
I honestly don't know. Your approach seems okay, if one forgets the minimum alarms granularity.

Is there a definitive way to measure "time to paint" for performance?

I'm testing various performance tweaks for a large website, and I need to quantify how long it takes from initial load to the document elements appearing (i.e. time to paint). Is there a good way to do this using Chrome's dev profiler?
To clarify, I need to know the total time from load to painted page.
You could do one of two things:
1) Use Dan Mayor's method. You can simply use new Date().getTime before and after the painting script and subtract them in order to find out how long the script took to complete. However, this may be subject to lag if the entire code lags. It's not necessarily the most accurate way, but it gets the job done. (However, you could create a separate function that calculates the time independently of the other script. See below:)
function findTime(done){
if (done==false){var time1 = new Date.getTime();}
if (done==true) {var time2 = new Date.getTime(); window.alert(time2-time1);}
}
Where done is a boolean parameter you would add after the script is complete.
2) Chrome has a nice developer's console with a timeline capability. Basically, open your Chrome browser and hit command+Shift+C (control+shift+C for windows), and click the timeline button. Then, click the little dot at the bottom of the console, and it should turn red. Refresh the page, and the timeline will start collecting all kinds of timing data for your scripts. Painting events are shown in green. Unfortunately, this is a third party solution.
In the end, there is no way to directly measure this time, due to different amounts of lag, different internet connectivity speeds, processor speeds, etc. However, these 2 methods come pretty close to the actual answer. You may want to test the scripts on different browsers and computers.
For starters, I would definitely familiarize myself with the "Net panel" in Firebug:
http://getfirebug.com/network
I understand that Chrome has a similar tool: Hit "F12" (or use the "wrench" icon):
https://developers.google.com/chrome-developer-tools/
You might want to look into the "DOMContentLoaded" event, this is what jQuery binds to to provide it's .ready() method. The basic idea is you will want to use Date.getTime() to record millisecond values, the first should be the last line of your document (for html downloaded marker). The second you want to call after onload, DOMContentLoaded, loaded and other DOM ready state events.
Quick example (end of your html output):
<script type="text/javascript">
window.downloadComplete = new Date().getTime();
document.onload = function() { window.domParseComplete = new Date().getTime(); }
window.onload = function { window.renderComplete = new Date().getTime(); }
window.paintTime = window.renderComplete - window.downloadComplete;
</script>
In this example window.downloadComplete will be the millisecond when the DOM has finished downloading, window.domParseComplete is the millisecond when the DOM has been parsed and window.renderComplete is the millisecond when the window reports it's rendering is complete. The window.paintTime is just the number of milliseconds calculated from these millisecond time's.

Preloading images (in Chrome) [duplicate]

I am pre-loading some images and then using them in a lightbox. The problem I have is that although the images are loading, they aren't being displayed by the browser.
This issue is specific to Chrome. It has persisted through Chrome 8 - 10, and I've been trying on and off to fix it all this time and have got nowhere.
I have read these similar questions,
Chrome not displaying images though assets are being delivered to browser
2 Minor Crossbrowser CSS Issues. Background images not displaying in Google Chrome?
JavaScript preloaded images are getting reloaded
Which all detail similar behaviour but in Chrome for Mac. Whereas this is happening in Windows.
All other browsers seem to be fine.
If you have Firefox and Chrome open, load the page in Firefox, and then in Chrome, the images appear.
Once you have manually loaded the images, using the Webkit webdev toolbar thingy, they always show up
All the links the images and such are fine and working
Clearing everything from Chrome doesn't seem to make any difference (cache, history, etc)
If anyone has any ideas it would be fantastically helpfull, as I'm literally all out of options here.
PS, Apologies if there are late replies, I'm off on holiday for a week tomorrow! :D
Update
Here is the javascript function which is preloading the images.
var preloaded = new Array();
function preload_images() {
for (var i = 0; i < arguments.length; i++){
document.write('<');
document.write('img src=\"'+arguments[i]+'\" style=\"display:none;\">');
};
};
Update
I'm still having issues with this, and I've removed the whole preloading images function. Perhaps delivering a style sheet via document.write() isn't the best way?
Chrome might not be preloading them as it's writing to the DOM with no display, so it might be intelligent enough to realise it doesn't need to be rendered. Try this instead:
var preloaded = new Array();
function preload_images(){
for (var x = 0; x < preload_images.arguments.length; x++)
{
preloaded[x] = new Image();
preloaded[x].src = preload_images.arguments[x];
}
}
The Javascript Image object has a lot of useful functions as well you might find useful:
http://www.javascriptkit.com/jsref/image.shtml
onabort()
Code is executed when user aborts the
downloading of the image.
onerror()
Code is executed when an error occurs
with the loading of the image (ie: not
found). Example(s)
onload()
Code is executed when the image
successfully and completely downloads.
And then you also have the complete property which true/false tells you if the image has fully (pre)loaded.
It turns out that Chrome takes into account the HTTP Caching and discards any preloaded images immediately after preload if the Caching is incorrectly set to expire.
In my case I am generating the images dynamically and by default the response was sent to the browser with immediate expiration.
To fix it I had to set the following below:
Response.Cache.SetExpires(DateTime.Now.AddYears(1));
Response.Cache.SetCacheability(HttpCacheability.Public);
return File(jpegStream, "image/jpeg");