Let's say I would like to synchronize two videos and avoid echos. I meant that the two tracks should stay in sync as though playing a regular video file with audio.
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls=""></video><br>
<p>Current Time:<span id="aTime"></span></p><br>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls=""></video><br>
<p>Current Time:<span id="bTime"></span></p><br>
<button onclick="playM()">Play</button>
<button onclick="pauseM()">Pause</button>
<script>
var a = document.getElementById("A");
var b = document.getElementById("B");
function playM() {
a.play();
b.play();
}
function pauseM() {
a.pause();
b.pause();
}
a.ontimeupdate = function() {
document.getElementById("aTime").innerHTML = a.currentTime;
};
b.ontimeupdate = function() {
document.getElementById("bTime").innerHTML = b.currentTime;
};
a.onseeked = function() {
b.currentTime= a.currentTime;
};
b.onseeked = function() {
a.currentTime = b.currentTime;
};
</script>
Update
After some experimentation, I've discovered that the an offset of mere microseconds is great, but not really necessary for syncing videos. In Demo 2 we have video tag A and B. A has 4 eventListener() and video B as the callback. play(), pause(), and seek are synced between A and B with A being the "master" and B the "slave".
Demo 2
<!DOCTYPE html>
<html>
<head>
<style>
html {
font: 400 16px/1.5 Consolas
}
section {
display: flex;
justify-content: space-around;
width: 100%;
height: calc(100% - 160px);
}
button {
padding: 0;
border: 0;
}
</style>
</head>
<body>
<section>
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='240' height='135'></video>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='240' height='135'></video>
</section>
<script>
var A = document.getElementById("A");
var B = document.getElementById("B");
A.addEventListener("play", function() {
B.play();
});
A.addEventListener("pause", function() {
B.pause();
});
A.addEventListener("seeking", function() {
B.currentTime = A.currentTime;
});
A.addEventListener("seeked", function() {
B.currentTime = A.currentTime;
});
</script>
</body>
</html>
JavaScript is synchronous, meaning that it processes one thing at a time. Syncing media is possible by using Promises which allows asynchronous operations but it's syntax is unintuitive and down right difficult. Fortunately async and await just got released in all major browsers* only a couple of months ago. All of the behavior and flow of Promises are in await. Here's the basic syntax involved using 2 functions asynchronously:
async function functionName() {
var A = await functionA();
var B = await functionB();
var C = A + B;
return C;
}
Details are commented in Demo
References are at the bottom of post
Demo
/* For details on how this demo controls the <form>,
|| see HTMLFormControlsCollection in References
*/
var x = document.forms.ui.elements;
var playM = x.playM;
var pauseM = x.pauseM;
/* Register the buttons to the click event
|| callback is asyncCall()
|| Register a video tag to the ended event
|| callback is just an anonymous function to
|| display 'IDLE' message when the videos have ended
*/
/* Avoid the use of on event handlers, use event
|| listeners instead. For details on Event Listeners
|| see addEventListener() in References
*/
playM.addEventListener('click', asyncCall, false);
pauseM.addEventListener('click', asyncCall, false);
document.querySelector('video').addEventListener('ended', function(e) {
x.display.value = 'IDLE';
}, false);
/* This callback is an Async Function which uses a key
|| word called "await". await waits for a function
|| to start then moves on to the next await to
|| see when it's ready to start. The players are
|| playing asynchronously (i.e. congruently, i.e i.e. in
|| parallel). Normally JavaScript is synchronous because
|| the evaluation and execution of a function is the
|| only thing a browser would do, so everything else
|| had to wait their turn. That is called: "blocking".
|| While await is waiting, the browser is allowed to do
|| other processing. For details on async and await,
|| see References.
*/
async function asyncCall(e) {
var A = document.getElementById("A");
var B = document.getElementById("B");
var status;
/* if/if else condition to determin which button was
|| actually clicked. Use e.target to get the origin
|| of event (i.e. clicked button). For details on
|| Event.target, see References
*/
// if the button's #id is 'playM'...
if (e.target.id === 'playM') {
var mediaA = await mPlay(A);
x.outA.value = performance.now(mediaA);
var mediaB = await mPlay(B);
x.outB.value = performance.now(mediaB);
status = mPlay(B);
// otherwise if the button's #id is 'pauseM'...
} else if (e.target.id === 'pauseM') {
var mediaA = await mIdle(A);
x.outA.value = performance.now(mediaA);
var mediaB = await mIdle(B);
x.outB.value = performance.now(mediaB);
status = mIdle(B);
} else {
status = 'IDLE';
}
x.display.value = status;
return status;
}
// Simple function used in asyncCall() to play
function mPlay(ele) {
var state = 'PLAYING';
ele.play();
return state;
}
// Simple function used in asyncCall() to pause
function mIdle(ele) {
var state = 'IDLE';
ele.pause();
return state;
}
html {
font: 400 16px/1.5 Consolas
}
section {
display: flex;
justify-content: space-around;
width: 100%;
height: calc(100% - 160px);
}
button {
padding: 0;
border: 0;
}
#playM:before {
content: '▶';
font-size: 32px
}
#pauseM::before {
content: '⏸';
font-size: 32px;
}
<section>
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='160' height='90'></video>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='160' height='90'></video>
</section>
<form id='ui'>
<fieldset>
<legend>Asynchronous Playback</legend>
<button id='playM' type='button'></button>
<button id='pauseM' type='button'></button>
<output id='display'></output><br><br>
<label for='outA'>Source A: </label>
<output id='outA'></output><br><br>
<label for='outB'>Source B: </label>
<output id='outB'></output><br><br>
</fieldset>
</form>
References
async function() {... await
HTMLFormControlsCollection
Event.target
Event.target .addEventListener( 'event', function, false )
You can use plain JavaScript for this. A good starting point and reference would be W3C Schools. The currentTime property with an oncuechange function should get you started in checking changes in the timeline and seeking.
Although, I don't understand your restrictions (if any) so don't know why you wouldn't just use a video file with the audio and video already synced.
Related
I have created an automatic slideshow - which starts after clicking "menu item". I'm looking for a way to "turn it off", when clicking different "menu item". The whole problem can be abstracted to a simple example:
Constructing functionality for "stop" <li> (that would probably utilize stopInterval). I can't come up with a solution, would anyone have an idea ?
const li1 = document.getElementById("li1")
li1.addEventListener("click", slideShowAbstract)
function slideShowAbstract(e) {
const y = setInterval(()=> console.log("playing"), 2000)
}
ul {
display: flex;
justify-content: center;
list-style-type: none;
}
li {
margin: 1rem;
}
li:hover {
cursor: pointer;
}
<ul>
<li id="li1">play</li>
<li id="li2">stop</li>
</ul>
a better way ?
to avoid having global variables that can be jostled by side effects, use an object, to which you can add your useful methods.
const
btPlay = document.querySelector('#bt-play')
, player = (()=> // IIFE for object { play(), stop() } method
{
let // inside Object values ( closure )
refIntv = 0
, counter = 0
, onProcess = false // security to avoid multiple setInterval processes
;
function playerAction() // inside private function
{
console.clear()
console.log( 'playing', ++counter)
}
return {
play()
{
if (onProcess) return // security to avoid doing setInterval() twice
onProcess = true
counter = 0
console.clear()
console.log('start playing')
refIntv = setInterval( playerAction , 2000)
}
, stop()
{
if (!onProcess) return // security to avoid doing clearInterval() twice
clearInterval( refIntv )
onProcess = false
console.clear()
console.log('stop playing')
}
}
})();
btPlay.onclick =_=>
{
if (btPlay.classList.toggle('stopped')) player.play()
else player.stop()
}
button {
margin : 1em 3em;
width : 5em;
}
#bt-play::after {
content : 'play';
}
#bt-play.stopped::after {
content : 'stop';
}
<h5> case 1: same button for start and stop </h5>
<button id="bt-play"></button>
<!-- control by interface : same button for start and stop -->
<hr>
<h5> case 2: 2 buttons </h5>
<button onclick="player.play()">play</button>
<button onclick="player.stop()">stop</button>
interface control:
if you have 2 buttons (start + stop), the user can click 2 times on the start button and you
you end up with 2 overlapping interval processes (or more) without the possibility of finding the reference of the previous setInterval since this variable has been replaced to reference the process of the following interval
if not you can also add a test verifying that there is no running interval process before.
You can declare the y outside so that you can access it from multiple handlers.
const li1 = document.getElementById("li1")
const stopElement = document.getElementById("stopButton")
let intervalTimer;
li1.addEventListener("click", slideShowAbstract);
stopElement.addEventListener('click', stopSlideShow);
function slideShowAbstract(e) {
intervalTimer = setInterval(() => console.log("playing"), 2000);
}
function stopSlideShow(){
clearInterval(intervalTimer);
}
Details commented in example
// Reference both items
const li1 = document.getElementById("li1");
const li2 = document.getElementById("li2");
// Bind both items to click event but call different handlers
li1.addEventListener("click", start);
li2.addEventListener("click", stop);
// Declare interval ID
let y;
// Define time interval
let t = 2000;
// Define counter
let tick = 0;
// Define the function to run on each interval
const log = () => console.log(t * tick++);
// Define the event handler called from li1
function start(e) {
// If the tag clicked was #li1 and y isn't defined yet...
if (e.target.matches('#li1') && !y) {
// ...Initiate interval to call log()
y = setInterval(log, t);
}
}
// Define the event handler called from li2
function stop(e) {
// If user clicked #li2...
if (e.target.matches('#li2')) {
// ...Stop interval...
clearInterval(y);
// ...reset interval ID
y = null;
}
}
ul {
display: flex;
justify-content: center;
list-style-type: none;
}
li {
margin: 1rem;
}
li:hover {
cursor: pointer;
}
<ul>
<li id="li1">play</li>
<li id="li2">stop</li>
</ul>
const startBtn = document.getElementById("start")
const stopBtn = document.getElementById("stop")
const timer = {
timerId : undefined,
idx : 0,
start(){
if(timer.timerId)
timer.stop();
timer.timerId = setInterval(()=> {
document.getElementById("status").textContent = timer.idx++;
console.log(timer.idx);
}, 1000);
},
stop(){
if(timer.timerId){
clearInterval(timer.timerId);
timer.idx = 0;
timer.timerId = undefined;
document.getElementById("status").textContent = timer.idx;
}
}
}
startBtn.addEventListener("click", timer.start);
stopBtn.addEventListener("click", timer.stop);
<button id="start">start</button>
<button id="stop">stop</button>
<br/>
<span id="status">
</span>
When I play and pause and play again it does not play because
speechSynthesis.pause() does not make speechSynthesis.paused true which should make it true.
I've checked the docs it says
The paused read-only property of the SpeechSynthesis interface is a Boolean that returns true if the SpeechSynthesis object is in a paused state, or false if not.
meaning the line speechSynthesis.pause() didnt set it to true
Sample below:
const playButton = document.getElementById("play-button");
const pauseButton = document.getElementById("pause-button");
const stopButton = document.getElementById("stop-button");
const textInput = document.getElementById("text");
const speedInput = document.getElementById("speed");
const status = document.getElementById("status");
let currentCharacter;
const utterance = new SpeechSynthesisUtterance();
utterance.addEventListener("end", () => {
textInput.disabled = false;
})
utterance.addEventListener("bounary", e => {
currentCharacter = e.charIndex;
})
playButton.addEventListener("click", () => {
playText(textInput.value);
})
pauseButton.addEventListener("click", pauseText);
stopButton.addEventListener("click", stopText);
speedInput.addEventListener("input", () => {
stopText();
playText(utterance.text.substring(currentCharacter))
})
function playText(text) {
if (speechSynthesis.paused && speechSynthesis.speaking) {
status.innerHTML = "resumed";
return speechSynthesis.resume()
}
status.innerHTML = "played";
if (speechSynthesis.speaking) return
utterance.text = text;
utterance.rate = speedInput.value || 1;
textInput.disabled = true;
speechSynthesis.speak(utterance);
}
function pauseText() {
if (speechSynthesis.speaking) {
status.innerHTML = "paused";
speechSynthesis.pause() //
}
}
function stopText() {
status.innerHTML = "stopped";
speechSynthesis.resume()
speechSynthesis.cancel()
}
body {
width: 90%;
margin: 0 auto;
margin-top: 1rem;
}
#text {
width: 100%;
height: 50vh;
}
<textarea name="text" id="text"></textarea>
<label for="speed">Speed</label>
<input type="number" name="speed" id="speed" min=".5" max="3" step=".5" value="1">
<button id="play-button">Play</button>
<button id="pause-button">Pause</button>
<button id="stop-button">Stop</button>
<span id="status"></span>
You can use this code to see the statuses upon clicking Play, Pause and Stop. The statues are then updated when the relevent event is triggered. I.e. when you click Play the statuses are shown once upon clicking and again upon the onstart event being fired.
You'll see that there is a difference between these two for example when you click Pause the paused flag is false until the onpause event is triggered a moment later.
Given that chrome has problems and there are timing issues I suggest that you keep it simple and have start, pause, resume and cancel buttons with their own functions.
const showStatus = (btn) => {
const statuses = document.createTextNode(`
${btn}:
Pending: ${speechSynthesis.pending},
Speaking: ${speechSynthesis.speaking},
Paused: ${speechSynthesis.paused}`);
const p = document.createElement('p');
p.appendChild(statuses);
data.insertBefore(p, data.firstElementChild);
};
play.addEventListener("click", (e) => {
const u = new SpeechSynthesisUtterance(
"1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
);
speechSynthesis.speak(u);
showStatus(e.target.innerText);
u.onstart = () => showStatus('On start');
u.onpause = () => showStatus('On pause');
u.onresume = () => showStatus('On resume');
u.onend = () => showStatus('On end');
u.onerror = (err) => showStatus('On error ' + err);
});
pause.addEventListener("click", (e) => {
speechSynthesis.pause();
showStatus(e.target.innerText);
});
resume.addEventListener("click", (e) => {
speechSynthesis.resume();
showStatus(e.target.innerText);
});
ssCancel.addEventListener('click', (e) => {
speechSynthesis.cancel();
showStatus(e.target.innerText);
});
showStatus('Upon load');
<button id="play">Play</button>
<button id="pause">Pause</button>
<button id="resume">Resume</button>
<button id="ssCancel">Cancel</button>
<div id="data"></div>
I had the same problem. My reading of the docs did not coincide with what I experienced. I ended up simply setting my own variable to keep track of whether there is a pause. Of note, the speaking property can be used to find if the utterance has not been started, or has finished. That coupled with my own variable keeping track of what to do when the user presses the pause button allowed me to get a stop, play and pause feature.
Edit: This works for me in Edge Browser. I plan to update after I try in others.
const synth = window.speechSynthesis;
let myPauseProperty = false;
let utterThis;
function stop() {
myPauseProperty = false;
synth.cancel(utterThis);
}
function play() {
if ((myPauseProperty === true)&&(synth.speaking===true)) {//alredy started not ended
//speech somewhere in the middle, and paused, needs resumed
synth.resume();
myPauseProperty=false;
}
else if (synth.speaking===false) {
//not started or has ended, user expects to start play
utterThis = new SpeechSynthesisUtterance(document.getElementById("text-area").value);
synth.speak(utterThis);
myPauseProperty=false;
}
}
function pause() {
if ((myPauseProperty === true)&&(synth.speaking===true)) {
//speech somewhere in middle of phrase and paused, user wants unpause
synth.resume();
myPauseProperty = false;
}
else if ((myPauseProperty === false)&&(synth.speaking===true)) {
//speech somewhere in middle of phrase and unpaused, user wants pause
synth.pause()
myPauseProperty=true;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<textarea id="text-area">Put your text here and try playing.</textarea>
<nav>
<button onclick="stop();">[]</button>
<button onclick="play();">|></button>
<button onclick="pause();">||</button>
</nav>
</body>
</html>
The following code works on Chrome 80.0 and Firefox 74.0 (OSX 10.14.6). However, on OSX Safari 13.0.5 or on iOS (testing in Chrome, Safari), the <div> element never turns blue, indicating that the onended callback does not fire. Is this a bug?
const ctx = new (window.AudioContext || window.webkitAudioContext)();
const buff = ctx.createBuffer(1, 32, ctx.sampleRate);
const buffSource = ctx.createBufferSource();
buffSource.buffer = buff;
buffSource.loop = false;
// attempt to add an event listener to the buffer source
buffSource.addEventListener('ended', () => {
document.getElementById('test').style.backgroundColor = 'blue';
});
// another slight variation using the named function
function changeBackground() {
document.getElementById('test').style.backgroundColor = 'blue';
}
buffSource.addEventListener('ended', changeBackground);
// the documentation suggestion modifying the function directly
buffSource.onended = function(){
document.getElementById('test').style.backgroundColor = 'blue';
};
// maybe binding would help?
buffSource.onended = function(){
document.getElementById('test').style.backgroundColor = 'blue';
}.bind(this);
document.getElementById('button').onclick = (e) => {
ctx.resume();
buffSource.start();
document.getElementById('message').innerText = "Pressed Button";
};
#test {
background-color: red;
width: 500px;
height: 500px;
}
#button {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<body>
<button id = 'button'>Click me</button>
<div id = 'test'></div>
<div id = 'message'></div>
</body>
</html>
Safari doesn't fire the ended event if the AudioBufferSourceNode is not connected.
buffSource.connect(ctx.destination);
Executing this line before calling start() should make it work.
I'd like to have a like/dislike hyperlink to display different contents on my page: when clicking 'like', displays 'good'; when clicking 'dislike', displays 'bad'. My code is like this:
<html>
<head>
<script>
function Homepage(){
this.like = document.getElementById("like");
this.dislike = document.getElementById("dislike");
Homepage.prototype = {
constructor: Homepage,
likeGame: function(event){
if(this.like.style.display == "none"){
this.like.style.display = "block";
}
event.preventDefault();
},
dislikeGame: function(event){
if(this.dislike.style.display == "none"){
this.dislike.style.display = "block";
}
event.preventDefault();
},
setListeners: function(){
console.log('in listen');
document.getElementById("hyperLike").addEventListener("click", this.likeGame);
document.getElementById("hyperDislike").addEventListener("click", this.dislikeGame);
}
}
}
</script>
</head>
<body>
<p style="display:block">
<a id="hyperLike" href="";>Like</a>/<a id="hyperDislike" href="";>Dislike</a> the game.
</p>
<p id="like" style="display:none">
good
</p>
<p id="dislike" style="display:none">
bad
</p>
<script>
var homepage = new Homepage();
window.onload = homepage.setListeners;
</script>
</body>
</html>
However it does not work. Clicking hyperlinks has no reaction. I added console.log in setListeners, nothing logged, so it does not even go into setListeners. What's the problem here?
I have another none-OO version, which is basically same code, it works.
The problem is that this.like inside the likeGame() function is not the same as this.like in the Homepage() function, because a function has its own scope. One way to solve this is to use arrow functions as methods. Now this will always refer to Homepage.
function Homepage() {
this.like = document.getElementById("like");
this.dislike = document.getElementById("dislike");
this.likeGame = (event) => {
if (this.like.style.display == "none") {
this.dislike.style.display = "none"
this.like.style.display = "block";
}
event.preventDefault();
};
this.dislikeGame = (event) => {
if (this.dislike.style.display == "none") {
this.like.style.display = "none"
this.dislike.style.display = "block";
}
event.preventDefault();
};
this.setListeners = () => {
console.log('in listen');
document.getElementById("hyperLike").addEventListener("click", this.likeGame);
document.getElementById("hyperDislike").addEventListener("click", this.dislikeGame);
}
}
var homepage = new Homepage();
window.addEventListener("load", () => {
homepage.setListeners();
})
<html>
<body>
<p style="display:block">
<a id="hyperLike" href="">Like</a>/<a id="hyperDislike" href="" ;>Dislike</a> the game.
</p>
<p id="like" style="display:none">
good
</p>
<p id="dislike" style="display:none">
bad
</p>
</body>
</html>
The following demo can bind multiple elements to any applicable event and callback function. The advantage of using this class is that the parameters selector, event, and callback can be anything and there's no extra steps to take for multiple listeners.
Demo
Details are commented in demo
This is a modification of the code featured in this article.
// Define class
class Homepage {
// Pass a CSS selector
constructor(selector) {
// Reference selector
const elements = document.querySelectorAll(selector);
// Get amount of elements
this.length = elements.length;
// Merge the constructor and elements
Object.assign(this, elements);
}
// Pass a callback function
each(callback) {
// Iterate elements...
for (let node of Array.from(this)) {
// ...call callback function fore each element...
callback.call(node);
}
// ...make the method chainable
return this;
}
// Pass event and callback
bind(event, callback) {
// Iterate constructor...
return this.each(function() {
// ...regiter each element to the event and assign callback
this.addEventListener(event, callback, false);
});
}
};
// Instantiate Homepage class
const likeHate = selector => new Homepage(selector);
// Callback rate()
const rate = e => {
// Reference clicked element
const tgt = e.target;
// If the clicked has .btn class...
if (tgt.matches('.btn')) {
// ...get the clicked value...
const val = e.target.value;
// ...reference article#rate...
const rate = document.getElementById('rate');
// ...assign the value of clicked to [data-rate] of #rate
rate.dataset.rate = val;
// If the value of clicked is 'Superior' = thumbs up/down
let icon = val === 'Superior' ? '👍' : '👎';
// Assign icon to [data-icon] of #rate
rate.dataset.icon = icon;
}
}
/*
Call the .bind() method on all .btn and register the click event
to each .btn. Assign rate() as callback function.
*/
likeHate('.btn').bind('click', rate);
html,
body {
font: 700 16px/1.3 Raleway;
}
header {
font-size: 1.5rem;
margin: 10px 0;
}
.btn {
border: 0 none transparent;
background: none;
cursor: pointer;
font: inherit;
margin: 0;
}
.btn:hover {
color: blue;
text-decoration: underline;
}
.btn:focus {
outline: none;
}
#rate {
font-size: 1.5rem;
}
#rate::before {
content: attr(data-icon)'\a0';
}
#rate::after {
content: attr(data-rate)'\a0';
}
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">
</head>
<body>
<header>
<button class='btn' value='Superior'>Like</button>/<button class='btn' value='Inferior'>Hate</button> the game.
</header>
<article id="rate" data-icon='' data-rate=''></article>
</body>
</html>
When the selection of the dropdown does change, I would like to:
1) show some GUI blocking overlay via a div over the whole website
2) then process some code
3) then hide the overlay.
The problem is that when I write this logic in the eventlistener-function then onChange 2) would execute, then the GUI performs the updates of 1) and 3), because the GUI is only updating in Javascript when all functions are executed. That's not the correct order and not what I want.
So I thought I introduce a Webworker, but it turned out that the Webworker does exeactly nothing, the order is still wrong.
demo_workers.js:
postMessage("show_overlay_runtime");
postMessage("do_stuff");
postMessage("hide_overlay_runtime");
<!DOCTYPE html>
<html>
<head>
<style>
#overlay {
position: absolute;
top:200px;
left:0;
background-color: #000;
display:none;
width:100%;
height:200px;
}
</style>
</head>
<body>
<div id="overlay"></div>
<select id="my_dropdown">
<option>option1</option>
<option>option2</option>
</select>
<script>
let my_dropdown = document.getElementById('my_dropdown');
my_dropdown.addEventListener('change', function (e) {
dropdown_network_change_response();
}, false);
var workers = {};
function dropdown_network_change_response()
{
let worker_name = "worker1";
startWorker(worker_name, "demo_workers.js");
workers[worker_name].onmessage = function(event) {
if(event.data === "show_overlay_runtime") {
document.getElementById('overlay').style.display = "flex";
}
else if (event.data === "do_stuff") {
for(let i = 0; i < 1000000; i++) {
}
}
else if (event.data === "hide_overlay_runtime") {
document.getElementById('overlay').style.display = "none";
}
alert("test");
};
}
function startWorker(worker_name, file) {
if(typeof(Worker) !== "undefined") {
if(typeof(workers[worker_name]) == "undefined") {
workers[worker_name] = new Worker(file);
}
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker(worker_name) {
workers[worker_name].terminate();
workers[worker_name] = undefined;
}
</script>
</body>
</html>
So how can I achieve what I mentioned above in Javascript?
You can use setTimeout to give the GUI a chance to do its updating before certain code starts; for example:
function afterGUIupdate() {
postMessage("do_stuff");
postMessage("hide_overlay_runtime");
}
postMessage("show_overlay_runtime");
setTimeout( afterGUIupdate, 1 );
Technically, your code finishes after calling setTimeout, so the GUI can do its updating. Then the timeout kicks in, executing the code you want to occur after that.