1

I am new to JavaScript! I am trying to make an extremely naive blocking statement in a JavaScript program. I think JavaScript is single threaded (mostly, except for things like setTimeout), and synchronous within a code block, so I expected that I could block execution of my code with a while loop. I do not want to use setTimeout because I'm not sure it will be reliably precise enough to do what I want.

Let me explain. I have a button with class="playback", which should trigger a series of sounds to play. The callback makes an AJAX request, and then hands data to playbackRecording(). This function accepts a list of objects which have two attributes: key_pressed (helps determines which sound to play, but is not important for this issue), and time_to_next_key (how many milliseconds to wait until the next sound is played). actionApp() is the function that causes the sound to actually get played.

My expectation: The first sound is played. Then a short amount of time passes and the next action happens. Repeat until finished.

What actually happens: An amount of time elapses that equals the sum of time_to_next_key for all keypresses, then all the sounds are played at the end.

function playbackRecording(content) {
    var waitTime = 0;
    var keypress = content[0];
    actionApp(keypress.key_pressed);

    for (var i = 1; i < content.length; i++) {
        waitTime += keypress.time_to_next_key;
        keypress = content[i];

        var end = Date.now() + waitTime;

        while(Date.now() < end) {}
        actionApp(keypress.key_pressed);
    }
}

function playbackLinkClicked(evt) {
    var urlString = '/fetch_recording/' + this.id;

    $.get(urlString, function(data){
        if (data.status === 'success') {
            playbackRecording(data.content);
        } else {
            alert('Could not load recording.');
        }
    });
}

$('.playback').click(playbackLinkClicked);

What I am missing?

mmmmmmaya
  • 33
  • 6
  • How are you triggering the sounds? It may be that the triggering process is being blocked by your while loop. – user1937198 Aug 12 '16 at 23:53
  • Probably, the sounds are played asynchronously. So your synchronous code blocks the sounds. – Oriol Aug 12 '16 at 23:55
  • Learn about the event loop: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop . – Felix Kling Aug 12 '16 at 23:57
  • JavaScript is pretty bad for stuff that depends on super accurate timing.. see here: http://stackoverflow.com/questions/196027/is-there-a-more-accurate-way-to-create-a-javascript-timer-than-settimeout But if you know for sure that your code will execute within the interval, then you can probably get away with using setInterval. See here for a great explanation of how setInterval works: http://javascript.info/tutorial/settimeout-setinterval – James Pan Aug 13 '16 at 00:10
  • *"I do not want to use setTimeout because I'm not sure it will be reliably precise enough to do what I want."* - Use it anyway. Don't use `setInterval()` if you want precise control, use `setTimeout()` and calculate the appropriate delay based on the current time. A blocking loop like `while(Date.now() < end) {}` is always a bad idea because it freezes the whole browser, giving a bad user experience. – nnnnnn Aug 13 '16 at 00:14
  • If you have to "wait" for playback of an audio clip to finish, you can use an [onended](https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events) event handler on the audio element (the "ended" event is sent when the "ended" attribute is set) . If you need silence between sound clips, use [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout). Don't use blocking loops ;-) – traktor Aug 13 '16 at 02:26

1 Answers1

4

Playing the sound is done by asynchronous code (I don't know exactly what actionApp() does, but the behavior you describe is consistent with this, and it's how most interactive code works in Javascript). So when you call actionApp(), it's putting this code on the event queue. It will not actually play anything until Javascript returns to the main event loop.

The while loop is synchronous, so your code doesn't return until all of them are finished. Each time it calls actionApp() it adds another sound to the event queue. Then when it finishes, all the queued actions get executed.

Barmar
  • 741,623
  • 53
  • 500
  • 612