Выполнение JavaScript в реальном времени без зависания браузера - PullRequest
4 голосов
/ 27 октября 2010

Я пытаюсь написать простой музыкальный секвенсор в Javascript.

Звуки будут воспроизводиться SoundManager2

Я быстро понял, что setTimeout и setInterval бесполезныдля такого рода времени.Их точность просто недостаточно хороша.

Вместо этого я пытаюсь вот что:

Создать очередь звуковых событий (массив 2d [ note , время ])

Обработка очереди в цикле while

В псевдокоде это может выглядеть так:

// The queue of time/note values (millisecs)
var q = [[0, C], [250, D], [500, E]]

var begin = (new Date).getTime()

while(q.length > 0 ){
    var now = (new Date).getTime()
    var eventTime = q[0][0] + begin

    if( now >= eventTime){

        playNote(q[0][1]) // Play the note  
        q.shift()       // Now that the note has been played, discard it.
    }
}

Через отладку яобнаружил, что этот метод кажется достаточно точным (вызов playNote выполняется именно в то время, в которое он должен).

Однако, пока воспроизводится «последовательность», все остальные Javascript (включая бит, который фактически делает звук)приостановлено, что вряд ли является сюрпризом.

Это означает, что у меня есть тишина столько времени, сколько требуется для запуска последовательности, а затем выполняются ВСЕ вызовы playNote.

У меня естьпопытался изолировать цикл while в своей собственной функции, а затем вызвать его через setTimeout, в надежде, что это создаст фоновый поток, выполняющий свою собственную вещь (а именно, проигрывание последовательности), не останавливая все остальные JS-операции.Это не работает

Я также пытался вызвать функцию playNote, используя setTimeout, в надежде, что хотя пользовательский интерфейс действительно заморожен, по крайней мере, последовательность воспроизводится правильно, но это тоже не работает.

Я также попробовал комбинацию, но, как вы уже, наверное, догадались, она тоже не работает.

Итак, мой вопрос:

Как я могу иметь очередьсобытий, обработанных с точной синхронизацией, при этом НЕ останавливая выполнение всех других кодов во время выполнения

Ответы [ 2 ]

1 голос
/ 27 октября 2010

Я не знаю, есть ли решение для старых браузеров, но веб-работники предназначены для параллельного выполнения в JavaScript.

Они поддерживаются в последних версиях Chrome иFirefox, я не знаю о других браузерах.

0 голосов
/ 27 октября 2010

Если вы замените цикл while на рекурсивную функцию (она не должна выполняться самостоятельно), браузер не остановится.

(function foo (q) {
    var now = (new Date).getTime(),
        eventTime = q[0][0] + begin;
    if (q.length > 0) {
        if (now >= eventTime) {
            playNote(q[0][1]); // Play the note
            q.shift(); // Discard played note
        }
        return foo(q); // Pass q into the next round
    } else {
        return; // End the "loop"
    }
}(q));

Редактировать: Проблема с рекурсивными вызовами + точность таймера должна решаться setInterval:

var timer = setInterval(function foo () {
    var now = (new Date).getTime(),
        eventTime = q[0][0] + begin;
    if (q.length > 0) {
        if (now >= eventTime) {
            playNote(q[0][1]); // Play the note
            q.shift(); // Discard played note
        }
    } else {
        clearInterval(timer); // End the "loop"
    }
}, 10); // This is in ms (10 is just a random number)
...