JavaScript Button click event image hiding is delayed

AI Thread Summary
The discussion centers on a web project where a button labeled 'Harmonics' is intended to hide an image upon being clicked, but the image remains visible until a sleep function completes. The issue arises because JavaScript does not update the browser display until after the event handler returns, which prevents immediate visual changes. The sleep function, initially used for demonstration, is not effective in this context.Participants clarify that JavaScript lacks a true sleep function, and suggest using setTimeout to create a delay without blocking the main thread. An asynchronous approach is recommended, allowing the image to be hidden immediately while still managing timing for audio playback. The proposed solution involves implementing a sleep function that returns a promise, enabling the event handler to hide the image and continue processing without delay. This method successfully resolves the issue, allowing for immediate visual feedback when the button is clicked.
Bob Walance
Insights Author
Gold Member
Messages
82
Reaction score
55
TL;DR Summary
The style.visibility = 'hidden' image attribute is not taking effect until end of sleep function
My webpage project has a button labeled 'Harmonics' with a mouse-click event. I want an image to be hidden as soon as the button is clicked, however this doesn't happen.

Here's a snippet of the html. It doesn't matter what order the two Javascript functions are called. The 'hidden' attribute for the image does not take effect until the sleep function completes.

gwd.Harmonics = function(event) {
document.getElementsByClassName('gwd-img-17a0')[0].style.visibility = 'hidden'; // hide the image
sleep(2000); // delay for 2000ms

Can anyone tell me if this can be fixed so that the image is hidden as soon as the button is clicked?
 
Technology news on Phys.org
PeterDonis said:
Why is the sleep function there at all?
I'm just using a sleep function here to simply demonstrate the issue. The real project is playing a tone and I need to know when the tone has ended. There is an event-driven mechanism for this but it is unreliable so I'm using a simple date/time-based timer in order to know when to start the next tone.
 
Bob Walance said:
I'm just using a sleep function here to simply demonstrate the issue.
Unfortunately, the issue you are running up against, at least as I understand how the Javascript engine works, is simple: your function is an event handler and Javascript doesn't update the browser display to reflect any changes the event handler makes until after the handler returns. So you can't put any kind of time delay tracking mechanism in an event handler because it delays updating the browser display.

Bob Walance said:
There is an event-driven mechanism for this but it is unreliable
How so?
 
PeterDonis said:
Unfortunately, the issue you are running up against, at least as I understand how the Javascript engine works, is simple: your function is an event handler and Javascript doesn't update the browser display to reflect any changes the event handler makes until after the handler returns. So you can't put any kind of time delay tracking mechanism in an event handler because it delays updating the browser display.
PeterDonis said:
How so?
1 - I was afraid of that. That's really how it appears to be behaving. Darn.
2 - I think that the audioContext tone generation 'onend' event issue is related to "Javascript doesn't update the browser display..." operation that you pointed out.

My app's purpose is to demonstrate the difference, musically, between equal-temperament tuning and simple harmonics of an instrument note (nature). The part of the app that plays one tone or chord works perfectly. When I need a sequence of tones (e.g. in a musical scale) then I run into these issues.

I have a complete application written and working in Python, but I can't distribute the Python code here. That's why I'm attempting to get it to work in a web browser.
 
Bob Walance said:
2 - I think that the audioContext tone generation 'onend' event issue is related to "Javascript doesn't update the browser display..." operation that you pointed out.
There is no AudioContext onend event. Perhaps you are thinking of the AudioScheduledSourceNode ended event: https://developer.mozilla.org/en-US/docs/Web/API/AudioScheduledSourceNode/ended_event

Bob Walance said:
My app's purpose is to demonstrate the difference, musically, between equal-temperament tuning and simple harmonics of an instrument note (nature). The part of the app that plays one tone or chord works perfectly. When I need a sequence of tones (e.g. in a musical scale) then I run into these issues.
Perhaps you might be better off using the tone.js module I showed you on another thread.

Bob Walance said:
I have a complete application written and working in Python, but I can't distribute the Python code here. That's why I'm attempting to get it to work in a web browser.
Programming for the web is very different from programming in Python, you need to completely change your mindset to write asynchronous, event driven code rather than the blocking code you are used to.
 
pbuk said:
There is no AudioContext onend event. Perhaps you are thinking of the AudioScheduledSourceNode ended event: https://developer.mozilla.org/en-US/docs/Web/API/AudioScheduledSourceNode/
Perhaps you might be better off using the tone.js module I showed you on another thread.

Programming for the web is very different from programming in Python, you need to completely change your mindset to write asynchronous, event driven code rather than the blocking code you are used to.

pbuk said:
There is no AudioContext onend event. Perhaps you are thinking of the AudioScheduledSourceNode ended event: https://developer.mozilla.org/en-US/docs/Web/API/AudioScheduledSourceNode/ended_eventPerhaps you might be better off using the tone.js module I showed you on another thread.Programming for the web is very different from programming in Python, you need to completely change your mindset to write asynchronous, event driven code rather than the blocking code you are used to.

I did look at tone.js but I don't think it'll do what I want. For example, I need to play two major chords:
A + C# + E
and
440Hz + 550Hz + 660Hz

They both sound close but the latter is much sweeter sounding. The beat frequency produced between the C# and the fifth harmonic of 110Hz is very obvious when it's juxtaposed with the natural major third interval.
 
jedishrfu said:
Maybe this will work:

https://www.codegrepper.com/code-ex...+to+reload+page+on+button+click+in+javascript

It's likely an ugly solution, but from it, you might find a better way.

Thanks. I'm aware of this and am utilizing it to make repeated musical scales more reliable (I'm not sure where the real issue is there).

I should have been a software engineer. Their life is SO much easier overall. They can just sit at their computers all day sipping their Daiquiris while us EEs have to go into the lab and inhale lead fumes.
 
  • #10
Sadly, you have a romanticized view of software engineers. Yes, we can code but a lot of time is spent tracking down your own or other people's misguided coding mistakes, and some can be downright impossible to find in a timely fashion.

So revel in the fact that you are a talented engineer learning the ropes of programming.
 
  • Like
Likes Bob Walance
  • #11
There is actually no sleep function in javascript. And if you keep javascript busy in a different fashion, all other activity is on hold as @PeterDonis already pointed out. Moreover, if you keep javascript busy for too long (a couple of seconds), the browser will complain that a script is causing trouble and ask if you want to kill it.

If you do want to sleep, then the relevant function is setTimeout, which takes a callback that will be called after a time. During this time all other activity resumes and the browser will display anything that was changed.

If you want to wait for it and continue what you were doing, then you can use:
Code:
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
gwd.Harmonics = async function(event) {
  document.getElementsByClassName('gwd-img-17a0')[0].style.visibility = 'hidden'; // hide the image
  await sleep(2000); // delay for 2000ms
  // Other processing
}
Note that the sleep is implemented using setTimeout, and all other activity will resume during this time so your element will immediately become invisible.
 
Last edited:
  • Love
Likes Bob Walance
  • #12
I like Serena said:
If you want to wait for it and continue what you were doing, then you can use:
Code:
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
gwd.Harmonics = async function(event) {
  document.getElementsByClassName('gwd-img-17a0')[0].style.visibility = 'hidden'; // hide the image
  await sleep(2000); // delay for 2000ms
  // Other processing
}
Note that the sleep is implemented using setTimeout, and all other activity will resume during this time so your element will immediately become invisible.
YES! Your solution works perfectly. I was just about to give up and try a different approach, but you completely solved my problem.

Thank you very much, liker of Serena.
 
  • Like
Likes I like Serena

Similar threads

Replies
3
Views
2K
Replies
2
Views
5K
Back
Top